@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
@@ -14,81 +14,192 @@ import './moni-icon.js';
14
14
  import './moni-progress.js';
15
15
 
16
16
  /**
17
- * Material Design 3 Textarea component.
17
+ * Componente Material Design 3 Textarea (Área de texto).
18
18
  *
19
- * A multi-line text input field designed for collecting longer amounts of text,
20
- * such as comments, descriptions, or messages.
19
+ * Un campo de entrada de texto multilínea diseñado para recolectar cantidades mayores de texto,
20
+ * como comentarios, descripciones o mensajes.
21
21
  *
22
- * **M3 spec reference:** `m3-docs/components/text-fields/specs.md`
22
+ * **Referencia a la especificación M3:** `m3-docs/components/text-fields/specs.md`
23
23
  *
24
- * **Visual architecture:**
25
- * It shares the exact same `.field` shell and styling engine as
26
- * `<moni-text-field>`, but internally renders a native `<textarea>` instead
27
- * of an `<input>`. This ensures visual consistency across all form elements
28
- * regarding floating labels, helper text, error states, and icons.
24
+ * **Arquitectura visual:**
25
+ * Comparte exactamente el mismo contenedor `.field` y motor de estilos que
26
+ * `<moni-text-field>`, pero internamente renderiza un `<textarea>` nativo en lugar
27
+ * de un `<input>`. Esto asegura la consistencia visual en todos los elementos del formulario
28
+ * en cuanto a etiquetas flotantes, texto de ayuda, estados de error e iconos.
29
29
  *
30
- * **Character Counter:**
31
- * If the `maxlength` attribute is set, the textarea automatically displays
32
- * a character counter (`{current length} / {maxlength}`) positioned at the
33
- * trailing edge of the supporting text area (bottom right). This can be
34
- * suppressed by setting the `no-counter` attribute.
30
+ * **Contador de caracteres:**
31
+ * Si se establece el atributo `maxlength`, el área de texto muestra automáticamente
32
+ * un contador de caracteres (`{longitud actual} / {maxlength}`) ubicado en el
33
+ * borde final (trailing) del área de texto de soporte (abajo a la derecha). Esto puede
34
+ * suprimirse estableciendo el atributo `no-counter`.
35
35
  *
36
- * **State management:**
37
- * This component is purely visual and presentational. It reflects attributes
38
- * down to the native textarea, but it does NOT attach internal `@input` or
39
- * `@change` listeners. Consumers should attach standard DOM listeners directly
40
- * to this element to capture user input, just as they would with a native
41
- * textarea.
36
+ * **Gestión del estado:**
37
+ * Este componente es puramente visual y representacional. Refleja los atributos
38
+ * hacia el textarea nativo, pero NO adjunta listeners internos para `@input` o
39
+ * `@change`. Los consumidores deben adjuntar listeners estándar del DOM directamente
40
+ * a este elemento para capturar la entrada del usuario, tal como lo harían con un
41
+ * textarea nativo.
42
42
  *
43
43
  * @example
44
44
  * ```html
45
- * <!-- Standard filled textarea -->
46
- * <moni-textarea label="Description" rows="4"></moni-textarea>
45
+ * <!-- Textarea llenado (filled) estándar -->
46
+ * <moni-textarea label="Descripción" rows="4"></moni-textarea>
47
47
  *
48
- * <!-- Outlined textarea with character counter -->
48
+ * <!-- Textarea contorneado (outlined) con contador de caracteres -->
49
49
  * <moni-textarea
50
50
  * variant="outlined"
51
- * label="Bio"
51
+ * label="Biografía"
52
52
  * maxlength="160"
53
53
  * ></moni-textarea>
54
54
  * ```
55
55
  *
56
- * @csspart field - The outer `.field` div container.
57
- * @csspart input - The native `<textarea>` element.
58
- * @csspart label - The floating `<label>` element.
59
- * @csspart helper - The helper/error text area.
60
- * @csspart counter - The character counter element.
56
+ * @csspart field - El contenedor div `.field` exterior.
57
+ * @csspart input - El elemento `<textarea>` nativo.
58
+ * @csspart label - El elemento `<label>` flotante.
59
+ * @csspart helper - El área de texto de ayuda/error.
60
+ * @csspart counter - El elemento contador de caracteres.
61
61
  */
62
62
  @customElement('moni-textarea')
63
63
  export class MoniTextarea extends MoniElement {
64
+ static formAssociated = true;
65
+ private _internals: ElementInternals;
66
+
67
+ constructor() {
68
+ super();
69
+ this._internals = this.attachInternals();
70
+ }
71
+
72
+ /**
73
+ * El nombre del textarea, enviado con los datos del formulario.
74
+ * @type {string}
75
+ */
64
76
  @property({ reflect: true }) name = '';
77
+
78
+ /**
79
+ * El texto de la etiqueta flotante.
80
+ * @type {string}
81
+ */
65
82
  @property({ reflect: true }) label = '';
83
+
84
+ /**
85
+ * Variante visual del área de texto.
86
+ * @type {'filled' | 'outlined'}
87
+ * @default 'filled'
88
+ */
66
89
  @property({ reflect: true }) variant: 'filled' | 'outlined' = 'filled';
90
+
91
+ /**
92
+ * Define las dimensiones del área de texto.
93
+ * @type {'small' | 'medium' | 'large' | 'extra'}
94
+ * @default 'medium'
95
+ */
67
96
  @property({ reflect: true })
68
97
  size: 'small' | 'medium' | 'large' | 'extra' = 'medium';
98
+
99
+ /**
100
+ * Forma del radio del borde (border-radius) del campo.
101
+ * @type {'round' | 'square' | 'no-round'}
102
+ * @default 'no-round'
103
+ */
69
104
  @property({ reflect: true })
70
105
  shape: 'round' | 'square' | 'no-round' = 'no-round';
106
+
107
+ /**
108
+ * Nombre del icono inicial (leading) (Material Symbols).
109
+ * @type {string}
110
+ */
71
111
  @property({ reflect: true }) icon = '';
112
+
113
+ /**
114
+ * Nombre del icono final (trailing) (Material Symbols).
115
+ * @type {string}
116
+ */
72
117
  @property({ reflect: true, attribute: 'trailing-icon' }) trailingIcon = '';
118
+
119
+ /**
120
+ * Prefijo de texto corto mostrado antes del valor del input.
121
+ * @type {string}
122
+ */
73
123
  @property({ reflect: true }) prefix = '';
124
+
125
+ /**
126
+ * Sufijo de texto corto mostrado después del valor del input.
127
+ * @type {string}
128
+ */
74
129
  @property({ reflect: true }) suffix = '';
130
+
131
+ /**
132
+ * Número por defecto de líneas de texto visibles.
133
+ * @type {number}
134
+ * @default 3
135
+ */
75
136
  @property({ type: Number, reflect: true }) rows = 3;
137
+
138
+ /**
139
+ * Número máximo de caracteres permitidos en el área de texto.
140
+ * También habilita la visualización del contador de caracteres a menos que `noCounter` sea true.
141
+ * @type {number | null}
142
+ */
76
143
  @property({ type: Number, reflect: true }) maxlength: number | null = null;
144
+
145
+ /**
146
+ * Oculta la visualización del contador de caracteres cuando se establece `maxlength`.
147
+ * @type {boolean}
148
+ */
77
149
  @property({ type: Boolean, reflect: true, attribute: 'no-counter' })
78
150
  noCounter = false;
151
+
152
+ /**
153
+ * Si es true, muestra un indicador de carga (progreso circular) al final.
154
+ * @type {boolean}
155
+ */
79
156
  @property({ type: Boolean, reflect: true }) loading = false;
157
+
158
+ /**
159
+ * Deshabilita el área de texto.
160
+ * @type {boolean}
161
+ */
80
162
  @property({ type: Boolean, reflect: true }) disabled = false;
163
+
164
+ /**
165
+ * Texto de ayuda mostrado debajo del campo.
166
+ * @type {string}
167
+ */
81
168
  @property({ reflect: true }) helper = '';
169
+
170
+ /**
171
+ * Texto de error mostrado debajo del campo cuando `error` es true.
172
+ * Sobrescribe el texto de ayuda.
173
+ * @type {string}
174
+ */
82
175
  @property({ reflect: true, attribute: 'error-text' }) errorText = '';
176
+
177
+ /**
178
+ * Si es true, establece el campo en un estado de error.
179
+ * @type {boolean}
180
+ */
83
181
  @property({ type: Boolean, reflect: true }) error = false;
182
+
183
+ /**
184
+ * El valor actual del área de texto.
185
+ * @type {string}
186
+ */
84
187
  @property({ reflect: true }) value = '';
188
+
189
+ /**
190
+ * Texto de marcador de posición (placeholder) mostrado cuando el textarea está vacío y la etiqueta es flotante.
191
+ * @type {string}
192
+ */
85
193
  @property({ reflect: true }) placeholder = '';
86
194
 
87
195
  @query('textarea') private _input!: HTMLTextAreaElement;
88
196
 
89
197
  override updated(changed: Map<string, unknown>) {
90
198
  if (this._input) {
91
- if (changed.has('value')) this._input.value = this.value;
199
+ if (changed.has('value')) {
200
+ this._input.value = this.value;
201
+ this._internals?.setFormValue?.(this.value);
202
+ }
92
203
  if (changed.has('disabled')) this._input.disabled = this.disabled;
93
204
  if (changed.has('maxlength') && this.maxlength != null) {
94
205
  this._input.maxLength = this.maxlength;
@@ -98,6 +209,19 @@ export class MoniTextarea extends MoniElement {
98
209
 
99
210
  static override styles = [sharedStyles, fieldStyles];
100
211
 
212
+ /**
213
+ * Renderiza el campo del área de texto con etiqueta, iconos de prefijo/sufijo y contador de caracteres.
214
+ *
215
+ * **Composición de `fieldClasses`:**
216
+ * Sigue la convención de nomenclatura field-styles. `prefix` se añade
217
+ * cuando el texto de `icon` o `prefix` está presente (desplaza el inicio en línea de la etiqueta).
218
+ * `suffix` se añade cuando `trailingIcon`, el texto `suffix` o `loading` es true.
219
+ *
220
+ * **Contador de caracteres:**
221
+ * `showCounter` es true cuando `maxlength > 0` y `noCounter` no está configurado.
222
+ * El contador muestra `${this.value.length} / ${this.maxlength}` y puede volverse rojo
223
+ * (vía CSS `invalid`) dependiendo de la validación.
224
+ */
101
225
  override render() {
102
226
  const hasLeading = Boolean(this.icon) || Boolean(this.prefix);
103
227
  const hasTrailing =
@@ -152,7 +276,7 @@ export class MoniTextarea extends MoniElement {
152
276
  >`
153
277
  : nothing;
154
278
 
155
- // M3 spec: supporting text on the left, character counter on the right.
279
+ // Especificación M3: texto de soporte a la izquierda, contador de caracteres a la derecha.
156
280
  const counter = showCounter
157
281
  ? html`<output part="counter" class="counter"
158
282
  >${this.value.length} / ${this.maxlength}</output
@@ -14,21 +14,21 @@ describe('moni-time-picker', () => {
14
14
  el.remove();
15
15
  });
16
16
 
17
- it('initializes with default values', async () => {
17
+ it('se inicializa con valores por defecto', async () => {
18
18
  await el.updateComplete;
19
19
  expect(el.value).toBe('00:00');
20
20
  expect(el.mode).toBe('dial');
21
21
  expect(el.use24Hour).toBe(false);
22
22
  });
23
23
 
24
- it('parses input value correctly', async () => {
24
+ it('analiza el valor de entrada correctamente', async () => {
25
25
  el.value = '14:45';
26
26
  await el.updateComplete;
27
- // Since use24Hour is false, PM is set
27
+ // Como use24Hour es false, PM está establecido
28
28
  expect(el.value).toBe('14:45');
29
29
  });
30
30
 
31
- it('toggles mode', async () => {
31
+ it('alterna el modo', async () => {
32
32
  await el.updateComplete;
33
33
  const toggleBtn = el.shadowRoot?.querySelector('.mode-toggle-btn') as HTMLButtonElement;
34
34
  expect(toggleBtn).toBeTruthy();
@@ -42,7 +42,7 @@ describe('moni-time-picker', () => {
42
42
  expect(el.mode).toBe('dial');
43
43
  });
44
44
 
45
- it('allows typing time in input mode', async () => {
45
+ it('permite escribir la hora en modo input', async () => {
46
46
  el.mode = 'input';
47
47
  el.use24Hour = true;
48
48
  await el.updateComplete;
@@ -12,40 +12,40 @@ import './moni-icon.js';
12
12
  import './moni-button.js';
13
13
 
14
14
  /**
15
- * Material Design 3 Time Picker component.
15
+ * Componente Material Design 3 Time Picker (Selector de hora).
16
16
  *
17
- * A highly interactive control that allows users to select a specific time.
18
- * It provides two distinct input modes:
19
- * 1. **Dial mode:** An interactive clock face where users can drag or click
20
- * to select hours and minutes.
21
- * 2. **Input mode:** Standard text inputs for precise keyboard entry.
17
+ * Un control altamente interactivo que permite a los usuarios seleccionar una hora específica.
18
+ * Proporciona dos modos de entrada distintos:
19
+ * 1. **Modo dial (analógico):** Una carátula de reloj interactiva donde los usuarios pueden arrastrar o hacer clic
20
+ * para seleccionar horas y minutos.
21
+ * 2. **Modo input (texto):** Entradas de texto estándar para una introducción precisa por teclado.
22
22
  *
23
- * **M3 spec reference:** `m3-docs/components/time-pickers/specs.md`
23
+ * **Referencia a la especificación M3:** `m3-docs/components/time-pickers/specs.md`
24
24
  *
25
- * **Time formats & modes:**
26
- * - The `value` property expects and always outputs a 24-hour formatted string
27
- * (`HH:MM`, e.g., `"14:30"`).
28
- * - Setting `use-24-hour` configures the visual presentation to use a 24-hour
29
- * clock dial (inner and outer rings) and removes the AM/PM toggle. Otherwise,
30
- * it uses a standard 12-hour dial with an AM/PM toggle.
25
+ * **Formatos de hora y modos:**
26
+ * - La propiedad `value` espera y siempre emite un string en formato de 24 horas
27
+ * (`HH:MM`, ej. `"14:30"`).
28
+ * - Establecer `use-24-hour` configura la presentación visual para usar un
29
+ * reloj de 24 horas (anillos interior y exterior) y elimina el selector AM/PM. De lo contrario,
30
+ * utiliza un dial estándar de 12 horas con un selector AM/PM.
31
31
  *
32
- * **Responsive design:**
33
- * The `orientation` attribute configures the layout. `vertical` stacks the
34
- * time display above the clock face, `horizontal` places them side-by-side,
35
- * and `auto` responds to the container/viewport width automatically.
32
+ * **Diseño responsivo:**
33
+ * El atributo `orientation` configura el diseño. `vertical` apila la
34
+ * visualización de la hora sobre la carátula del reloj, `horizontal` los coloca lado a lado,
35
+ * y `auto` responde automáticamente al ancho del contenedor/viewport.
36
36
  *
37
- * @fires change - Fired when the selected time changes interactively. The
38
- * `detail.value` contains the new time in `HH:MM` format.
39
- * @fires cancel - Fired when the 'Cancel' button is clicked.
40
- * @fires ok - Fired when the 'OK' button is clicked. The `detail.value`
41
- * contains the final confirmed time.
37
+ * @fires change - Se dispara cuando la hora seleccionada cambia interactivamente. El
38
+ * `detail.value` contiene la nueva hora en formato `HH:MM`.
39
+ * @fires cancel - Se dispara cuando se hace clic en el botón 'Cancelar'.
40
+ * @fires ok - Se dispara cuando se hace clic en el botón 'OK'. El `detail.value`
41
+ * contiene la hora final confirmada.
42
42
  *
43
43
  * @example
44
44
  * ```html
45
- * <!-- 12-hour format (AM/PM) -->
45
+ * <!-- Formato 12 horas (AM/PM) -->
46
46
  * <moni-time-picker value="14:30"></moni-time-picker>
47
47
  *
48
- * <!-- 24-hour format -->
48
+ * <!-- Formato 24 horas -->
49
49
  * <moni-time-picker use-24-hour value="14:30"></moni-time-picker>
50
50
  * ```
51
51
  */
@@ -66,12 +66,24 @@ export class MoniTimePicker extends MoniElement {
66
66
 
67
67
  private isDragging = false;
68
68
 
69
+ /**
70
+ * Hook del ciclo de vida (Lit) previo al renderizado.
71
+ *
72
+ * Si la propiedad externa `value` o el modo `use24Hour` cambian (vía binding o atributo HTML),
73
+ * dispara el `parseValue()` de inmediato para mantener sincronizado el estado interno de
74
+ * horas y minutos (y recalcular AM/PM) antes de mutar el DOM real.
75
+ */
69
76
  protected override willUpdate(changedProperties: PropertyValues) {
70
77
  if (changedProperties.has('value') || changedProperties.has('use24Hour')) {
71
78
  this.parseValue();
72
79
  }
73
80
  }
74
81
 
82
+ /**
83
+ * Interpreta el string `value` (formato "HH:MM") y lo descompone en enteros para
84
+ * el estado interno. Automáticamente corrige valores fuera de rango y determina
85
+ * si estamos en AM o PM (cuando no se usa formato de 24 horas).
86
+ */
75
87
  private parseValue() {
76
88
  const parts = this.value.split(':');
77
89
  let h = parseInt(parts[0], 10);
@@ -92,6 +104,11 @@ export class MoniTimePicker extends MoniElement {
92
104
  }
93
105
  }
94
106
 
107
+ /**
108
+ * Reconstruye el string `value` a partir del estado interno (`currentHour`, `currentMinute`).
109
+ * Formatea con ceros a la izquierda e incluye la lógica de conversión AM/PM a 24hrs
110
+ * para garantizar que el valor expuesto hacia afuera sea siempre un estándar ISO ("14:30").
111
+ */
95
112
  private updateValue() {
96
113
  let h = this.currentHour;
97
114
  const m = this.currentMinute;
@@ -101,7 +118,7 @@ export class MoniTimePicker extends MoniElement {
101
118
  if (h < 12) h += 12;
102
119
  } else {
103
120
  if (h === 12) h = 0;
104
- else if (h > 12) h -= 12; // Adjust if out of bounds
121
+ else if (h > 12) h -= 12; // Ajuste por si quedó fuera de límites
105
122
  }
106
123
  }
107
124
 
@@ -116,20 +133,41 @@ export class MoniTimePicker extends MoniElement {
116
133
  }));
117
134
  }
118
135
 
136
+ /**
137
+ * Alterna el modo de interacción visual entre el Reloj Analógico (dial)
138
+ * y el modo de Entrada de Texto manual (input).
139
+ */
119
140
  private toggleMode() {
120
141
  this.mode = this.mode === 'dial' ? 'input' : 'dial';
121
142
  }
122
143
 
144
+ /**
145
+ * Define el nivel de selección activo ('hour' o 'minute').
146
+ * Cambia dinámicamente qué anillo o qué matemáticas (12 vs 60 items)
147
+ * utilizará el componente principal y el reloj.
148
+ */
123
149
  private setSelection(type: 'hour' | 'minute') {
124
150
  this.activeSelection = type;
125
151
  }
126
152
 
153
+ /**
154
+ * Cambia forzosamente el periodo del día ('AM' o 'PM') cuando el usuario
155
+ * presiona los conmutadores laterales (sólo visible en formato 12h).
156
+ * Inmediatamente propaga el cambio hacia `updateValue()` para recalcular
157
+ * y despachar la hora formateada.
158
+ */
127
159
  private setPeriod(p: 'AM' | 'PM') {
128
160
  this.period = p;
129
161
  this.updateValue();
130
162
  }
131
163
 
132
164
  // Clock Math and Interaction
165
+ /**
166
+ * Inicia el proceso de arrastre en la carátula del reloj (Pointer Down).
167
+ * Utiliza `setPointerCapture` nativo para asegurar que el movimiento (drag) siga
168
+ * siendo rastreado aunque el puntero del usuario salga físicamente del contenedor,
169
+ * garantizando una interacción "Touch" a prueba de errores.
170
+ */
133
171
  private handleClockPointerDown(e: PointerEvent) {
134
172
  if (!this.clockFaceEl) return;
135
173
  this.isDragging = true;
@@ -138,42 +176,52 @@ export class MoniTimePicker extends MoniElement {
138
176
  this.handleClockPointerMove(e);
139
177
  }
140
178
 
179
+ /**
180
+ * Corazón matemático del reloj radial (Time Picker analógico).
181
+ * Convierte las coordenadas cartesianas del ratón/dedo en un ángulo polar (0-360º),
182
+ * y dependiendo si medimos horas o minutos, lo mapea al número correspondiente.
183
+ */
141
184
  private handleClockPointerMove(e: PointerEvent) {
142
185
  if (!this.isDragging || !this.clockFaceEl) return;
186
+
143
187
  const rect = this.clockFaceEl.getBoundingClientRect();
188
+ // Encontramos el centro geométrico absoluto del reloj
144
189
  const centerX = rect.left + rect.width / 2;
145
190
  const centerY = rect.top + rect.height / 2;
146
191
 
147
192
  const dx = e.clientX - centerX;
148
193
  const dy = e.clientY - centerY;
194
+ // Teorema de Pitágoras para saber a qué distancia del centro está apuntando el usuario
149
195
  const distance = Math.sqrt(dx * dx + dy * dy);
150
196
 
151
- // Calculate angle in degrees from 12 o'clock position (clockwise)
197
+ // Calculamos el ángulo en grados partiendo desde las 12 (sentido horario).
198
+ // Math.atan2 devuelve de -PI a PI, sumamos 90º para desfasar el origen arriba (eje Y).
152
199
  let angle = Math.atan2(dy, dx) * (180 / Math.PI) + 90;
153
200
  if (angle < 0) angle += 360;
154
201
 
155
202
  if (this.activeSelection === 'hour') {
156
203
  if (this.use24Hour) {
157
- // Outer circle for 13-00, inner circle for 1-12
204
+ // Reloj de 24 horas M3: Un círculo externo (13-00) y uno interno (1-12)
205
+ // El umbral (0.32) fue medido visualmente para coincidir con el diseño radial interno.
158
206
  const isInner = distance < rect.width * 0.32;
159
- let hour = Math.round(angle / 30) % 12;
207
+ let hour = Math.round(angle / 30) % 12; // 360 / 12 horas = 30 grados por hora
160
208
  if (hour === 0) hour = 12;
161
209
 
162
210
  if (isInner) {
163
- // Inner circle: 1 to 12
211
+ // Círculo interno: 1 a 12 (AM/PM)
164
212
  this.currentHour = hour;
165
213
  } else {
166
- // Outer circle: 13 to 00/24
214
+ // Círculo externo: 13 a 24 (donde las 24 = 0)
167
215
  this.currentHour = hour === 12 ? 0 : hour + 12;
168
216
  }
169
217
  } else {
170
- // 12-hour face: 1 to 12
218
+ // Reloj estándar de 12 horas: solo 1 a 12
171
219
  let hour = Math.round(angle / 30) % 12;
172
220
  if (hour === 0) hour = 12;
173
221
  this.currentHour = hour;
174
222
  }
175
223
  } else {
176
- // Minutes: 0 to 59
224
+ // Modo minutos: 360 / 60 minutos = 6 grados por minuto
177
225
  const minute = Math.round(angle / 6) % 60;
178
226
  this.currentMinute = minute;
179
227
  }
@@ -181,12 +229,19 @@ export class MoniTimePicker extends MoniElement {
181
229
  this.updateValue();
182
230
  }
183
231
 
232
+ /**
233
+ * Finaliza la interacción de arrastre en la carátula del reloj (Pointer Up).
234
+ *
235
+ * Como heurística de usabilidad, si el usuario acaba de seleccionar la Hora,
236
+ * el componente espera 300ms y automáticamente transiciona a la vista de Minutos.
237
+ * Esto reduce los clics necesarios en interacciones de Time Pickers de un solo toque.
238
+ */
184
239
  private handleClockPointerUp() {
185
240
  if (this.isDragging) {
186
241
  this.isDragging = false;
187
242
  this.clockFaceEl?.classList.remove('dragging');
188
243
  if (this.activeSelection === 'hour') {
189
- // Automatically switch to minute selection after choosing hour
244
+ // Cambiar automáticamente a la selección de minutos después de elegir la hora
190
245
  setTimeout(() => {
191
246
  this.activeSelection = 'minute';
192
247
  }, 300);
@@ -194,6 +249,11 @@ export class MoniTimePicker extends MoniElement {
194
249
  }
195
250
  }
196
251
 
252
+ /**
253
+ * Handler para entradas directas desde el `<input>` de horas (Modo 'input' texto).
254
+ * Implementa clamping (límites mínimos y máximos) para asegurar que el usuario
255
+ * nunca pueda introducir valores erróneos mayores a 23h o menores a 0h.
256
+ */
197
257
  private handleHourInputChange(e: Event) {
198
258
  const target = e.target as HTMLInputElement;
199
259
  let val = parseInt(target.value, 10);
@@ -211,6 +271,10 @@ export class MoniTimePicker extends MoniElement {
211
271
  this.updateValue();
212
272
  }
213
273
 
274
+ /**
275
+ * Handler para entradas directas desde el `<input>` de minutos (Modo 'input' texto).
276
+ * Trunca cualquier input alfanumérico a enteros y realiza un clamp a 0-59.
277
+ */
214
278
  private handleMinuteInputChange(e: Event) {
215
279
  const target = e.target as HTMLInputElement;
216
280
  let val = parseInt(target.value, 10);
@@ -598,6 +662,13 @@ export class MoniTimePicker extends MoniElement {
598
662
  `
599
663
  ];
600
664
 
665
+ /**
666
+ * Renderizador de la carátula circular (Dial Face).
667
+ *
668
+ * Utiliza trigonometría básica (`sin` y `cos`) para distribuir los números equitativamente
669
+ * a lo largo del perímetro del círculo en CSS absoluto. En formato 24h, renderiza
670
+ * dos anillos concéntricos manipulando el radio relativo (`50%` vs `32%`).
671
+ */
601
672
  private renderDialClockFace() {
602
673
  const isHour = this.activeSelection === 'hour';
603
674
  let degrees = 0;
@@ -734,6 +805,30 @@ export class MoniTimePicker extends MoniElement {
734
805
  `;
735
806
  }
736
807
 
808
+ /**
809
+ * Renderiza el selector de hora (time picker) en modo `dial` o `input`.
810
+ *
811
+ * **Visualización 12 vs 24 horas:**
812
+ * `hourVal` convierte `currentHour` (0–23) al formato de visualización:
813
+ * - Modo 24 horas: string con ceros a la izquierda (ej. `'09'`, `'14'`).
814
+ * - Modo 12 horas: `0` → `12`, `13` → `1`, preservando la visualización AM/PM.
815
+ * `minuteVal` siempre tiene ceros a la izquierda para tener 2 dígitos.
816
+ *
817
+ * **Modo dial:**
818
+ * Renderiza una carátula de reloj DOM (HTML/CSS) con números distribuidos
819
+ * circularmente para cada hora/minuto. El sub-método `renderDialClockFace()`
820
+ * maneja la geometría y estilos que mueven la manecilla selectora mientras
821
+ * el usuario arrastra.
822
+ *
823
+ * **Modo input:**
824
+ * Renderiza dos elementos `<input type="number">` para la hora y el minuto con
825
+ * un selector AM/PM. El modo input es la alternativa (fallback) para accesibilidad
826
+ * y entornos no táctiles.
827
+ *
828
+ * **Alternador de modo:**
829
+ * Un icono de teclado cambia de modo `dial` a `input`; un icono de reloj
830
+ * cambia de vuelta.
831
+ */
737
832
  override render() {
738
833
  const hourVal = !this.use24Hour
739
834
  ? String(this.currentHour > 12 ? this.currentHour - 12 : this.currentHour === 0 ? 12 : this.currentHour).padStart(2, '0')
@@ -14,27 +14,27 @@ describe('moni-toolbar (P5.4 — recreated)', () => {
14
14
  el.remove();
15
15
  });
16
16
 
17
- it('defaults to type=standard', async () => {
17
+ it('type=standard por defecto', async () => {
18
18
  await el.updateComplete;
19
19
  expect(el.type).toBe('standard');
20
20
  expect(el.getAttribute('type')).toBe('standard');
21
21
  });
22
22
 
23
- it('renders a <header> container', async () => {
23
+ it('renderiza un contenedor <header>', async () => {
24
24
  await el.updateComplete;
25
25
  const header = el.shadowRoot?.querySelector('header');
26
26
  expect(header).toBeTruthy();
27
27
  expect(header?.getAttribute('part')).toBe('container');
28
28
  });
29
29
 
30
- it('renders the title attribute in the title span', async () => {
30
+ it('renderiza el atributo title en el span de título', async () => {
31
31
  el.title = 'My App';
32
32
  await el.updateComplete;
33
33
  const title = el.shadowRoot?.querySelector('[part="title"]');
34
34
  expect(title?.textContent?.trim()).toBe('My App');
35
35
  });
36
36
 
37
- it('supports slot fallback when title attribute is empty', async () => {
37
+ it('soporta slot de respaldo (fallback) cuando el atributo title está vacío', async () => {
38
38
  const heading = document.createElement('h1');
39
39
  heading.textContent = 'Slotted Title';
40
40
  el.appendChild(heading);
@@ -46,7 +46,7 @@ describe('moni-toolbar (P5.4 — recreated)', () => {
46
46
  expect(text).toBe('Slotted Title');
47
47
  });
48
48
 
49
- it('renders leading and trailing slots', async () => {
49
+ it('renderiza los slots leading y trailing', async () => {
50
50
  const leading = document.createElement('button');
51
51
  leading.setAttribute('slot', 'leading');
52
52
  leading.textContent = 'Menu';
@@ -66,7 +66,7 @@ describe('moni-toolbar (P5.4 — recreated)', () => {
66
66
  expect(trailingSlot?.assignedNodes({ flatten: true }).length).toBeGreaterThan(0);
67
67
  });
68
68
 
69
- it('switches to floating type', async () => {
69
+ it('cambia al tipo floating', async () => {
70
70
  el.type = 'floating';
71
71
  await el.updateComplete;
72
72
  expect(el.getAttribute('type')).toBe('floating');
@@ -74,13 +74,13 @@ describe('moni-toolbar (P5.4 — recreated)', () => {
74
74
  expect(header).toBeTruthy();
75
75
  });
76
76
 
77
- it('reflects scroll attribute', async () => {
77
+ it('refleja el atributo scroll', async () => {
78
78
  el.scrolled = true;
79
79
  await el.updateComplete;
80
80
  expect(el.hasAttribute('scroll')).toBe(true);
81
81
  });
82
82
 
83
- it('reserves a slot for the action-button', async () => {
83
+ it('reserva un slot para el action-button', async () => {
84
84
  const fab = document.createElement('button');
85
85
  fab.setAttribute('slot', 'action-button');
86
86
  fab.textContent = '+';