@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
@@ -16,7 +16,7 @@ describe('moni-button-group', () => {
16
16
  group.remove();
17
17
  });
18
18
 
19
- it('propagates size to children buttons', async () => {
19
+ it('propaga el tamaño a los botones hijos', async () => {
20
20
  group.size = 'large';
21
21
  const btn1 = document.createElement('moni-button') as MoniButton;
22
22
  const btn2 = document.createElement('moni-button') as MoniButton;
@@ -31,7 +31,7 @@ describe('moni-button-group', () => {
31
31
  expect(btn2.getAttribute('size')).toBe('large');
32
32
  });
33
33
 
34
- it('sets appropriate shapes for connected variant', async () => {
34
+ it('establece las formas apropiadas para la variante connected', async () => {
35
35
  group.variant = 'connected';
36
36
  const btn1 = document.createElement('moni-button') as MoniButton;
37
37
  const btn2 = document.createElement('moni-button') as MoniButton;
@@ -50,7 +50,7 @@ describe('moni-button-group', () => {
50
50
  expect(btn3.getAttribute('shape')).toBe('right-round-flat');
51
51
  });
52
52
 
53
- it('uses round shapes for connected variant when gap is set', async () => {
53
+ it('usa formas redondeadas para la variante connected cuando se establece un gap', async () => {
54
54
  group.variant = 'connected';
55
55
  group.gap = '8px';
56
56
  const btn1 = document.createElement('moni-button') as MoniButton;
@@ -66,7 +66,7 @@ describe('moni-button-group', () => {
66
66
  expect(btn2.getAttribute('shape')).toBe('right-round');
67
67
  });
68
68
 
69
- it('manages active toggles in single-select mode (multi=false)', async () => {
69
+ it('gestiona los toggles activos en modo de selección única (multi=false)', async () => {
70
70
  const btn1 = document.createElement('moni-button') as MoniButton;
71
71
  const btn2 = document.createElement('moni-button') as MoniButton;
72
72
  group.appendChild(btn1);
@@ -76,14 +76,14 @@ describe('moni-button-group', () => {
76
76
  await btn1.updateComplete;
77
77
  await btn2.updateComplete;
78
78
 
79
- // Click btn1
79
+ // Clic en btn1
80
80
  btn1.click();
81
81
  await btn1.updateComplete;
82
82
  await btn2.updateComplete;
83
83
  expect(btn1.active).toBe(true);
84
84
  expect(btn2.active).toBe(false);
85
85
 
86
- // Click btn2
86
+ // Clic en btn2
87
87
  btn2.click();
88
88
  await btn1.updateComplete;
89
89
  await btn2.updateComplete;
@@ -91,7 +91,7 @@ describe('moni-button-group', () => {
91
91
  expect(btn2.active).toBe(true);
92
92
  });
93
93
 
94
- it('manages active toggles in multi-select mode (multi=true)', async () => {
94
+ it('gestiona los toggles activos en modo de selección múltiple (multi=true)', async () => {
95
95
  group.multi = true;
96
96
  const btn1 = document.createElement('moni-button') as MoniButton;
97
97
  const btn2 = document.createElement('moni-button') as MoniButton;
@@ -110,38 +110,38 @@ describe('moni-button-group', () => {
110
110
  expect(btn2.active).toBe(true);
111
111
  });
112
112
 
113
- it('renders role="group" on the container by default (M3 a11y)', async () => {
113
+ it('renderiza role="group" en el contenedor por defecto (accesibilidad M3)', async () => {
114
114
  await group.updateComplete;
115
115
  const container = group.shadowRoot?.querySelector('[part="container"]');
116
116
  expect(container?.getAttribute('role')).toBe('group');
117
117
  });
118
118
 
119
- it('supports role="toolbar" override for app-action groups', async () => {
119
+ it('soporta la sobrescritura de role="toolbar" para grupos de acciones de la aplicación', async () => {
120
120
  group.role = 'toolbar';
121
121
  await group.updateComplete;
122
122
  const container = group.shadowRoot?.querySelector('[part="container"]');
123
123
  expect(container?.getAttribute('role')).toBe('toolbar');
124
124
  });
125
125
 
126
- it('forwards aria-label to the container', async () => {
126
+ it('reenvía aria-label al contenedor', async () => {
127
127
  group.label = 'Text formatting';
128
128
  await group.updateComplete;
129
129
  const container = group.shadowRoot?.querySelector('[part="container"]');
130
130
  expect(container?.getAttribute('aria-label')).toBe('Text formatting');
131
131
  });
132
132
 
133
- it('forwards aria-labelledby to the container', async () => {
133
+ it('reenvía aria-labelledby al contenedor', async () => {
134
134
  group.labelledBy = 'group-title';
135
135
  await group.updateComplete;
136
136
  const container = group.shadowRoot?.querySelector('[part="container"]');
137
137
  expect(container?.getAttribute('aria-labelledby')).toBe('group-title');
138
138
  });
139
139
 
140
- it('does not emit aria-label when label is empty (M3 a11y cleanliness)', async () => {
140
+ it('no emite aria-label cuando la etiqueta está vacía (limpieza de accesibilidad M3)', async () => {
141
141
  await group.updateComplete;
142
142
  const container = group.shadowRoot?.querySelector('[part="container"]');
143
- // aria-label attribute should be either absent or empty string;
144
- // using `nothing` in lit removes the attribute entirely.
143
+ // el atributo aria-label debería estar ausente o ser una cadena vacía;
144
+ // usar nothing en lit elimina el atributo por completo.
145
145
  const aria = container?.getAttribute('aria-label');
146
146
  expect(aria === null || aria === '').toBe(true);
147
147
  });
@@ -10,73 +10,107 @@ import { customElement, property, queryAssignedElements } from 'lit/decorators.j
10
10
  import { MoniElement, sharedStyles } from './_base/index.js';
11
11
 
12
12
  /**
13
- * Material Design 3 Button Group component.
13
+ * Componente Material Design 3 Button Group.
14
14
  *
15
- * Organizes multiple `<moni-button>` or `<moni-icon-button>` components
16
- * into a single row.
15
+ * Organiza múltiples componentes `<moni-button>` o `<moni-icon-button>`
16
+ * en una sola fila.
17
17
  *
18
- * **Variants:**
19
- * - `standard` (default) — A simple flex row with a gap between buttons.
20
- * - `connected` — The M3 Expressive replacement for segmented buttons. In this
21
- * mode, buttons share borders and form a single continuous pill shape. The
22
- * group manages the single/multi-select toggle state of its children.
18
+ * **Variantes:**
19
+ * - `standard` (por defecto) — Una fila flex simple con un espacio entre botones.
20
+ * - `connected` — El reemplazo de M3 Expressive para los botones segmentados. En este
21
+ * modo, los botones comparten bordes y forman una sola forma de píldora continua. El
22
+ * grupo gestiona el estado de selección única/múltiple de sus hijos.
23
23
  *
24
- * **`connected` variant details:**
25
- * - **Shape propagation:** The group automatically propagates M3 shape classes
26
- * (`left-round-flat`, `no-round`, `right-round-flat`) to its children so
27
- * they interlock seamlessly.
28
- * - **Toggle management:** The group listens to child clicks and toggles their
29
- * `active` attributes. When `multi=false` (default), only one button can be
30
- * active at a time (radio button behavior). When `multi=true`, multiple buttons
31
- * can be active (checkbox behavior).
32
- * - **Event propagation:** Fires a `'change'` event when the selection changes.
24
+ * **Detalles de la variante `connected`:**
25
+ * - **Propagación de forma:** El grupo propaga automáticamente las clases de forma M3
26
+ * (`left-round-flat`, `no-round`, `right-round-flat`) a sus hijos para
27
+ * que se entrelacen sin problemas.
28
+ * - **Gestión del interruptor:** El grupo escucha los clics de los hijos y cambia sus
29
+ * atributos `active`. Cuando `multi=false` (por defecto), solo un botón puede estar
30
+ * activo a la vez (comportamiento de radio button). Cuando `multi=true`, múltiples botones
31
+ * pueden estar activos (comportamiento de checkbox).
32
+ * - **Propagación de eventos:** Dispara un evento `'change'` cuando la selección cambia.
33
33
  *
34
- * **Accessibility:**
35
- * - Renders with `role="group"` (can be overridden to `toolbar` or `radiogroup`).
36
- * - Consumers should provide an `aria-label` or `aria-labelledby` attribute
37
- * to identify the group's purpose to assistive technologies.
34
+ * **Accesibilidad:**
35
+ * - Renderiza con `role="group"` (puede ser sobrescrito a `toolbar` o `radiogroup`).
36
+ * - Los consumidores deben proporcionar un atributo `aria-label` o `aria-labelledby`
37
+ * para identificar el propósito del grupo para las tecnologías de asistencia.
38
38
  *
39
- * @fires change - Fired when a button is clicked in `connected` mode and the
40
- * selection state updates.
39
+ * @fires change - Disparado cuando se hace clic en un botón en modo `connected` y el
40
+ * estado de selección se actualiza.
41
41
  *
42
42
  * @example
43
43
  * ```html
44
- * <!-- Connected single-select group -->
45
- * <moni-button-group variant="connected" label="Alignment">
44
+ * <!-- Grupo conectado de selección única -->
45
+ * <moni-button-group variant="connected" label="Alineación">
46
46
  * <moni-button icon="format_align_left" active></moni-button>
47
47
  * <moni-button icon="format_align_center"></moni-button>
48
48
  * <moni-button icon="format_align_right"></moni-button>
49
49
  * </moni-button-group>
50
50
  *
51
- * <!-- Standard button row -->
51
+ * <!-- Fila estándar de botones -->
52
52
  * <moni-button-group gap="1rem">
53
- * <moni-button variant="text">Cancel</moni-button>
54
- * <moni-button>Save</moni-button>
53
+ * <moni-button variant="text">Cancelar</moni-button>
54
+ * <moni-button>Guardar</moni-button>
55
55
  * </moni-button-group>
56
56
  * ```
57
57
  *
58
- * @slot default - The `<moni-button>` elements that make up the group.
58
+ * @slot default - Los elementos `<moni-button>` que conforman el grupo.
59
59
  */
60
60
  @customElement('moni-button-group')
61
61
  export class MoniButtonGroup extends MoniElement {
62
+ /**
63
+ * Variante visual del grupo de botones.
64
+ * - `standard`: Los elementos se espacian normalmente.
65
+ * - `connected`: Los elementos se unen con bordes colapsados y radios internos aplanados.
66
+ * @type {'standard' | 'connected'}
67
+ * @default 'standard'
68
+ */
62
69
  @property({ reflect: true })
63
70
  variant: 'standard' | 'connected' = 'standard';
64
71
 
72
+ /**
73
+ * Tamaño de los botones en el grupo. Si se especifica, se propaga hacia abajo a los hijos.
74
+ * @type {'xsmall' | 'small' | 'medium' | 'large' | 'xlarge' | 'extra'}
75
+ * @default 'medium'
76
+ */
65
77
  @property({ reflect: true })
66
78
  size: 'xsmall' | 'small' | 'medium' | 'large' | 'xlarge' | 'extra' = 'medium';
67
79
 
80
+ /**
81
+ * Permite que múltiples botones estén activos a la vez (solo aplica a grupos seleccionables).
82
+ * @type {boolean}
83
+ */
68
84
  @property({ type: Boolean, reflect: true })
69
85
  multi = false;
70
86
 
87
+ /**
88
+ * Espacio CSS personalizado entre botones (ej., '1rem').
89
+ * Solo se aplica cuando la variante es 'standard'.
90
+ * @type {string}
91
+ */
71
92
  @property()
72
93
  gap = '';
73
94
 
95
+ /**
96
+ * Rol ARIA del contenedor del grupo.
97
+ * @type {'group' | 'toolbar' | 'radiogroup'}
98
+ * @default 'group'
99
+ */
74
100
  @property({ reflect: true })
75
101
  role: 'group' | 'toolbar' | 'radiogroup' = 'group';
76
102
 
103
+ /**
104
+ * Una etiqueta accesible para el grupo (`aria-label`).
105
+ * @type {string}
106
+ */
77
107
  @property({ reflect: true })
78
108
  label = '';
79
109
 
110
+ /**
111
+ * ID de un elemento que etiqueta este grupo (`aria-labelledby`).
112
+ * @type {string}
113
+ */
80
114
  @property({ reflect: true, attribute: 'labelled-by' })
81
115
  labelledBy = '';
82
116
 
@@ -124,6 +158,11 @@ export class MoniButtonGroup extends MoniElement {
124
158
  `
125
159
  ];
126
160
 
161
+ /**
162
+ * Hook del ciclo de vida reactivo (Lit).
163
+ * Detecta alteraciones estructurales en el propio grupo (como `variant`, `size` o `gap`)
164
+ * y fuerza una re-sincronización de todos los botones hijos para aplicar las físicas CSS.
165
+ */
127
166
  protected override updated(changedProperties: Map<string | number | symbol, unknown>) {
128
167
  super.updated(changedProperties);
129
168
  if (changedProperties.has('variant') || changedProperties.has('size') || changedProperties.has('gap')) {
@@ -131,6 +170,11 @@ export class MoniButtonGroup extends MoniElement {
131
170
  }
132
171
  }
133
172
 
173
+ /**
174
+ * Manejador del slot interno (`<slot>`).
175
+ * Cuando el desarrollador inyecta dinámicamente o remueve botones en runtime,
176
+ * re-sincroniza las formas (shapes) y tamaños de todo el listado.
177
+ */
134
178
  private handleSlotChange() {
135
179
  this.updateChildren();
136
180
  }
@@ -146,6 +190,13 @@ export class MoniButtonGroup extends MoniElement {
146
190
  return gap;
147
191
  }
148
192
 
193
+ /**
194
+ * Sincronizador de Propiedades (Engine interno).
195
+ * Itera sobre cada botón hijo para transferirle jerárquicamente las configuraciones
196
+ * del grupo. Si el grupo es del tipo `connected` (botones pegados), evalúa matemáticamente
197
+ * la posición del índice actual (primero, en medio o último) e inyecta la propiedad `shape`
198
+ * correspondiente (`left-round-flat`, `inner-round`, etc.) para formar una cápsula unificada.
199
+ */
149
200
  private updateChildren() {
150
201
  const buttons = this.slottedButtons.filter(
151
202
  (el) => el.tagName.toLowerCase() === 'moni-button' || el.tagName.toLowerCase() === 'moni-icon-button'
@@ -188,6 +239,12 @@ export class MoniButtonGroup extends MoniElement {
188
239
  });
189
240
  }
190
241
 
242
+ /**
243
+ * Maneja la interacción táctil o de mouse (Pointer Down).
244
+ * Genera un micro-efecto físico (Squish effect). Cuando el usuario presiona un botón
245
+ * dentro de un listado estándar, empuja físicamente (`scaleX` / `translateX`) a los
246
+ * botones adyacentes para simular presión material y desplazamiento.
247
+ */
191
248
  private handlePointerDown(e: PointerEvent) {
192
249
  if (this.variant !== 'standard') return;
193
250
  const target = e.target as HTMLElement;
@@ -215,6 +272,11 @@ export class MoniButtonGroup extends MoniElement {
215
272
  }
216
273
  }
217
274
 
275
+ /**
276
+ * Conclusión de la interacción táctil (Pointer Up).
277
+ * Restaura todas las transformaciones elásticas aplicadas a los botones adyacentes
278
+ * a su estado nativo neutro.
279
+ */
218
280
  private handlePointerUp() {
219
281
  const buttons = this.slottedButtons.filter(
220
282
  (el) => el.tagName.toLowerCase() === 'moni-button' || el.tagName.toLowerCase() === 'moni-icon-button'
@@ -225,6 +287,11 @@ export class MoniButtonGroup extends MoniElement {
225
287
  });
226
288
  }
227
289
 
290
+ /**
291
+ * Interceptor de clics de delegación.
292
+ * En grupos de tipo 'segment', garantiza que solo un botón tenga la clase activa
293
+ * o el atributo encendido de forma excluyente, actuando como un gestor de radio-buttons.
294
+ */
228
295
  private handleClick(e: Event) {
229
296
  const target = e.target as HTMLElement;
230
297
  const clickedButton = target.closest('moni-button, moni-icon-button');
@@ -268,6 +335,17 @@ export class MoniButtonGroup extends MoniElement {
268
335
  );
269
336
  }
270
337
 
338
+ /**
339
+ * Renders the button group container with `role="group"` semantics.
340
+ *
341
+ * The group is a flex container that distributes its slotted `<moni-button>`
342
+ * or `<moni-button-segment>` children in a row or column (based on `orientation`).
343
+ * CSS handles the shared-border collapse between adjacent segments:
344
+ * - Middle segments use `border-radius: 0` and `margin-inline-start: -1px`
345
+ * to prevent doubled borders.
346
+ * - `_syncSegments()` in `firstUpdated()` injects `left-round` / `right-round`
347
+ * shape attributes into the first and last children for correct pill termination.
348
+ */
271
349
  override render() {
272
350
  const resolvedGap = this.getGapValue(this.gap);
273
351
  const inlineStyles = resolvedGap
@@ -11,46 +11,74 @@ import { MoniElement, sharedStyles } from './_base/index.js';
11
11
  import './moni-icon.js';
12
12
 
13
13
  /**
14
- * Material Design 3 Segmented Button component (Legacy).
14
+ * Componente Material Design 3 Segmented Button (Heredado).
15
15
  *
16
- * **Deprecation Notice:** The M3 spec (`m3-docs/components/segmented-buttons/overview.md`)
17
- * has replaced the bespoke segmented button component with standard buttons arranged
18
- * in a "connected" group. Please use `<moni-button-group variant="connected">`
19
- * containing standard `<moni-button>` elements instead of this component.
16
+ * **Aviso de obsolescencia:** La especificación M3 (`m3-docs/components/segmented-buttons/overview.md`)
17
+ * ha reemplazado el componente a medida "segmented button" con botones estándar organizados
18
+ * en un grupo "conectado". Por favor usa `<moni-button-group variant="connected">`
19
+ * conteniendo elementos `<moni-button>` estándar en lugar de este componente.
20
20
  *
21
- * This component remains for backwards compatibility but will be removed in a
22
- * future major release. It renders a single segment within a `<moni-segmented-button>`.
21
+ * Este componente permanece por compatibilidad hacia atrás pero será eliminado en una
22
+ * futura versión mayor. Renderiza un segmento único dentro de un `<moni-segmented-button>`.
23
23
  *
24
- * @deprecated Use `<moni-button-group variant="connected">` instead.
24
+ * @deprecated Usa `<moni-button-group variant="connected">` en su lugar.
25
25
  *
26
26
  * @example
27
27
  * ```html
28
- * <!-- Legacy usage (not recommended) -->
28
+ * <!-- Uso heredado (no recomendado) -->
29
29
  * <moni-segmented-button>
30
- * <moni-button-segment value="day" checked>Day</moni-button-segment>
31
- * <moni-button-segment value="week">Week</moni-button-segment>
30
+ * <moni-button-segment value="day" checked>Día</moni-button-segment>
31
+ * <moni-button-segment value="week">Semana</moni-button-segment>
32
32
  * </moni-segmented-button>
33
33
  * ```
34
34
  *
35
- * @slot default - The segment label text.
35
+ * @slot default - El texto de la etiqueta del segmento.
36
36
  */
37
37
  @customElement('moni-button-segment')
38
38
  export class MoniButtonSegment extends MoniElement {
39
+ /**
40
+ * Valor asociado con el segmento, usado por el grupo padre.
41
+ * @type {string}
42
+ * @default 'on'
43
+ */
39
44
  @property({ reflect: true })
40
45
  value = 'on';
41
46
 
47
+ /**
48
+ * Estado seleccionado del segmento.
49
+ * @type {boolean}
50
+ */
42
51
  @property({ type: Boolean, reflect: true })
43
52
  checked = false;
44
53
 
54
+ /**
55
+ * Tamaño del segmento (usualmente heredado del botón segmentado padre).
56
+ * @type {'xsmall' | 'small' | 'medium' | 'large' | 'xlarge' | 'extra'}
57
+ * @default 'medium'
58
+ */
45
59
  @property({ reflect: true })
46
60
  size: 'xsmall' | 'small' | 'medium' | 'large' | 'xlarge' | 'extra' = 'medium';
47
61
 
62
+ /**
63
+ * Deshabilita el segmento.
64
+ * @type {boolean}
65
+ */
48
66
  @property({ type: Boolean, reflect: true })
49
67
  disabled = false;
50
68
 
69
+ /**
70
+ * Índice posicional del segmento dentro del grupo.
71
+ * Determina la lógica de redondeo del border-radius.
72
+ * @type {'first' | 'middle' | 'last' | 'solo'}
73
+ * @default 'solo'
74
+ */
51
75
  @property({ reflect: true })
52
76
  position: 'first' | 'middle' | 'last' | 'solo' = 'solo';
53
77
 
78
+ /**
79
+ * Si es verdadero, oculta el icono de marca de verificación que normalmente reemplaza al icono inicial cuando se selecciona.
80
+ * @type {boolean}
81
+ */
54
82
  @property({ type: Boolean, reflect: true, attribute: 'hide-check' })
55
83
  hideCheck = false;
56
84
 
@@ -290,6 +318,19 @@ export class MoniButtonSegment extends MoniElement {
290
318
  `
291
319
  ];
292
320
 
321
+ /**
322
+ * Renders the segment as a `role="radio"` toggle button within its group.
323
+ *
324
+ * **`role="radio"` + `aria-checked`:**
325
+ * Per the ARIA Segmented Button pattern, each segment acts as a radio button
326
+ * (`role="radio"`, `aria-checked=${this.active}`) within a `role="radiogroup"`
327
+ * container (the parent `<moni-segmented-button>`).
328
+ *
329
+ * **Checkmark icon:**
330
+ * When `active=true`, a `<moni-icon name="check">` is prepended to the label
331
+ * to signal the selected state visually (M3 Segmented Button spec, Figure 5).
332
+ * This icon disappears with a `scale(0)` transition when `active=false`.
333
+ */
293
334
  override render() {
294
335
  return html`
295
336
  <button class="button ${this.size}" type="button" ?disabled=${this.disabled}>
@@ -14,13 +14,13 @@ describe('moni-button', () => {
14
14
  el.remove();
15
15
  });
16
16
 
17
- it('renders a native <button> by default', async () => {
17
+ it('renderiza un <button> nativo por defecto', async () => {
18
18
  await el.updateComplete;
19
19
  const button = el.shadowRoot?.querySelector('button');
20
20
  expect(button).toBeTruthy();
21
21
  });
22
22
 
23
- it('renders an <a> when href is set', async () => {
23
+ it('renderiza un <a> cuando el href está establecido', async () => {
24
24
  el.href = 'https://example.com';
25
25
  await el.updateComplete;
26
26
  const a = el.shadowRoot?.querySelector('a');
@@ -28,27 +28,27 @@ describe('moni-button', () => {
28
28
  expect(a?.getAttribute('href')).toBe('https://example.com');
29
29
  });
30
30
 
31
- it('applies shape=circle class on the button', async () => {
31
+ it('aplica la clase shape=circle en el botón', async () => {
32
32
  el.shape = 'circle';
33
33
  await el.updateComplete;
34
34
  const button = el.shadowRoot?.querySelector('button');
35
35
  expect(button?.classList.contains('circle')).toBe(true);
36
36
  });
37
37
 
38
- it('hides the label part when shape=circle (verifies the :host selector)', async () => {
38
+ it('oculta la parte del label cuando shape=circle (verifica el selector :host)', async () => {
39
39
  el.shape = 'circle';
40
40
  el.textContent = 'Click me';
41
41
  await el.updateComplete;
42
- // The :host([shape='circle']) [part='label'] rule lives in shadow
43
- // stylesheets. jsdom's getComputedStyle is limited so we verify the
44
- // structural condition: the host has the shape attribute reflected
45
- // and the [part='label'] element exists for slot content.
42
+ // La regla :host([shape='circle']) [part='label'] vive en las hojas de estilo
43
+ // shadow. getComputedStyle de jsdom está limitado, así que verificamos la
44
+ // condición estructural: el host tiene el atributo shape reflejado
45
+ // y el elemento [part='label'] existe para el contenido del slot.
46
46
  expect(el.getAttribute('shape')).toBe('circle');
47
47
  const label = el.shadowRoot?.querySelector('[part="label"]');
48
48
  expect(label).toBeTruthy();
49
49
  });
50
50
 
51
- it('keeps the label rendered when shape=square', async () => {
51
+ it('mantiene el label renderizado cuando shape=square', async () => {
52
52
  el.shape = 'square';
53
53
  el.textContent = 'Square';
54
54
  await el.updateComplete;
@@ -57,7 +57,7 @@ describe('moni-button', () => {
57
57
  expect(el.getAttribute('shape')).toBe('square');
58
58
  });
59
59
 
60
- it('applies shape=square class on the button', async () => {
60
+ it('aplica la clase shape=square en el botón', async () => {
61
61
  el.shape = 'square';
62
62
  await el.updateComplete;
63
63
  const button = el.shadowRoot?.querySelector('button');
@@ -65,7 +65,7 @@ describe('moni-button', () => {
65
65
  expect(button?.classList.contains('circle')).toBe(false);
66
66
  });
67
67
 
68
- it('applies shape=circle class on the button', async () => {
68
+ it('aplica la clase shape=circle en el botón', async () => {
69
69
  el.shape = 'circle';
70
70
  await el.updateComplete;
71
71
  const button = el.shadowRoot?.querySelector('button');
@@ -73,21 +73,21 @@ describe('moni-button', () => {
73
73
  expect(button?.classList.contains('square')).toBe(false);
74
74
  });
75
75
 
76
- it('applies variant class for outlined', async () => {
76
+ it('aplica la clase de variante para outlined', async () => {
77
77
  el.variant = 'outlined';
78
78
  await el.updateComplete;
79
79
  const button = el.shadowRoot?.querySelector('button');
80
80
  expect(button?.classList.contains('border')).toBe(true);
81
81
  });
82
82
 
83
- it('applies size class for large', async () => {
83
+ it('aplica la clase de tamaño para large', async () => {
84
84
  el.size = 'large';
85
85
  await el.updateComplete;
86
86
  const button = el.shadowRoot?.querySelector('button');
87
87
  expect(button?.classList.contains('large')).toBe(true);
88
88
  });
89
89
 
90
- it('renders an icon when icon attribute is set', async () => {
90
+ it('renderiza un ícono cuando el atributo icon está establecido', async () => {
91
91
  el.icon = 'add';
92
92
  await el.updateComplete;
93
93
  const icon = el.shadowRoot?.querySelector('.icon');
@@ -97,7 +97,7 @@ describe('moni-button', () => {
97
97
  expect(moniIcon?.getAttribute('name')).toBe('add');
98
98
  });
99
99
 
100
- it('shows a loading spinner alongside icon/label when loading=true', async () => {
100
+ it('muestra un spinner de carga junto al ícono/label cuando loading=true', async () => {
101
101
  el.loading = true;
102
102
  await el.updateComplete;
103
103
  const progress = el.shadowRoot?.querySelector('moni-progress');
@@ -108,7 +108,7 @@ describe('moni-button', () => {
108
108
  expect(label).toBeTruthy();
109
109
  });
110
110
 
111
- it('renders an <a> with the loading spinner when href + loading are set', async () => {
111
+ it('renderiza un <a> con el spinner de carga cuando href + loading están establecidos', async () => {
112
112
  el.href = '#';
113
113
  el.loading = true;
114
114
  await el.updateComplete;
@@ -118,14 +118,14 @@ describe('moni-button', () => {
118
118
  expect(progress).toBeTruthy();
119
119
  });
120
120
 
121
- it('sets aria-busy on the button when loading', async () => {
121
+ it('establece aria-busy en el botón cuando está cargando', async () => {
122
122
  el.loading = true;
123
123
  await el.updateComplete;
124
124
  const button = el.shadowRoot?.querySelector('button');
125
125
  expect(button?.getAttribute('aria-busy')).toBe('true');
126
126
  });
127
127
 
128
- it('forwards disabled to the native button', async () => {
128
+ it('reenvía disabled al botón nativo', async () => {
129
129
  el.disabled = true;
130
130
  await el.updateComplete;
131
131
  const button = el.shadowRoot?.querySelector(
@@ -134,23 +134,25 @@ describe('moni-button', () => {
134
134
  expect(button.disabled).toBe(true);
135
135
  });
136
136
 
137
- it('logs a deprecation warning when size="extra" is used (use size="xlarge" per M3)', async () => {
137
+ it('registra una advertencia de obsolescencia cuando se usa size="extra" (usar size="xlarge" según M3)', async () => {
138
+ (el.constructor as any)._deprecationWarned = false;
138
139
  const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
139
- el.remove();
140
- el.size = 'extra';
141
- document.body.appendChild(el);
142
- await el.updateComplete;
140
+ const extraBtn = document.createElement('moni-button') as MoniButton;
141
+ extraBtn.size = 'extra';
142
+ document.body.appendChild(extraBtn);
143
+ await extraBtn.updateComplete;
143
144
  const call = warnSpy.mock.calls.find((c) =>
144
145
  String(c[0]).includes('[moni-ui]') &&
145
146
  String(c[0]).includes('size="extra"')
146
147
  );
147
- expect(call, 'expected a deprecation warning to mention size="extra"').toBeTruthy();
148
+ expect(call, 'se esperaba que una advertencia de obsolescencia mencionara size="extra"').toBeTruthy();
149
+ extraBtn.remove();
148
150
  warnSpy.mockRestore();
149
151
  });
150
152
 
151
- it('does not log a deprecation warning for M3-compliant size values', async () => {
153
+ it('no registra una advertencia de obsolescencia para los valores de tamaño compatibles con M3', async () => {
152
154
  const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
153
- // Use a fresh size to ensure no M3-stale deprecation is logged.
155
+ // Usar un tamaño nuevo para asegurar que no se registre una obsolescencia obsoleta de M3.
154
156
  const fresh = document.createElement('moni-button') as MoniButton;
155
157
  fresh.size = 'xlarge';
156
158
  document.body.appendChild(fresh);