@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
@@ -15,85 +15,178 @@ import { customElement, property, state, query } from 'lit/decorators.js';
15
15
  import { ifDefined } from 'lit/directives/if-defined.js';
16
16
  import { classMap } from 'lit/directives/class-map.js';
17
17
  import { MoniElement, sharedStyles, fieldStyles } from './_base/index.js';
18
+ import { emitMoniEvent } from '../utils/event-emitter.js';
18
19
  import './moni-icon.js';
19
20
  import './moni-progress.js';
20
21
  import './moni-select-option.js';
21
22
  /**
22
- * Material Design 3 Select (Dropdown) component.
23
+ * Componente Material Design 3 Select (Menú Desplegable).
23
24
  *
24
- * A fully-featured custom select dropdown with searchability, option groups,
25
- * keyboard navigation, animation, and optional mobile drawer/sheet mode.
26
- * Replaces the native `<select>` element with a fully styled, accessible
27
- * M3-compliant alternative.
25
+ * Un menú desplegable select personalizado completo con capacidad de búsqueda, grupos de opciones,
26
+ * navegación por teclado, animación y un modo de cajón/hoja (drawer/sheet) móvil opcional.
27
+ * Reemplaza el elemento nativo `<select>` con una alternativa completamente estilizada y accesible
28
+ * que cumple con M3.
28
29
  *
29
- * **M3 spec reference:** `m3-docs/components/menus/specs.md` (dropdown menus)
30
+ * **Referencia a la especificación M3:** `m3-docs/components/menus/specs.md` (menús desplegables)
30
31
  *
31
- * **Feature summary:**
32
- * - Filled and outlined variants matching the M3 text field styles.
33
- * - Floating label with the standard field-styles floating label animation.
34
- * - Searchable mode: `searchable` attribute adds an inline filter input.
35
- * - Option groups: slot `<moni-select-group>` elements for hierarchical options.
36
- * - Mobile drawer: `drawer` attribute opens options in a `<moni-bottom-sheet>`
37
- * instead of a dropdown popup, ideal for touch UIs.
38
- * - Keyboard navigation: Arrow keys, Enter, Escape, and Tab per ARIA combobox.
39
- * - Loading state: `loading` shows an indeterminate circular progress.
40
- * - Multi-value support: `multiple` enables multiple selection.
32
+ * **Resumen de características:**
33
+ * - Variantes Filled y Outlined que coinciden con los estilos de campo de texto de M3.
34
+ * - Etiqueta flotante (floating label) con la animación estándar de etiqueta flotante de estilos de campo.
35
+ * - Modo de búsqueda: el atributo `searchable` agrega un campo de entrada de filtro en línea.
36
+ * - Grupos de opciones: elementos `<moni-select-group>` en el slot para opciones jerárquicas.
37
+ * - Cajón móvil: el atributo `drawer` abre las opciones en un `<moni-bottom-sheet>`
38
+ * en lugar de un popup desplegable, ideal para interfaces táctiles (touch UIs).
39
+ * - Navegación por teclado: Teclas de flecha, Enter, Escape y Tab según combobox de ARIA.
40
+ * - Estado de carga: `loading` muestra un progreso circular indeterminado.
41
+ * - Soporte multi-valor: `multiple` permite selección múltiple.
41
42
  *
42
- * **Option sources:**
43
- * Options can be provided in two ways:
44
- * 1. **Slotted `<moni-select-option>` elements** (default, recommended for SSR).
45
- * 2. **`options` property** a `DropdownNode[]` array for fully programmatic control.
43
+ * **Fuentes de opciones:**
44
+ * Las opciones se pueden proporcionar de dos maneras:
45
+ * 1. **Elementos `<moni-select-option>` en la ranura (slot)** (por defecto, recomendado para SSR).
46
+ * 2. **Propiedad `options`**un array de `DropdownNode[]` para un control completamente programático.
46
47
  *
47
- * **Value binding:**
48
- * The `value` property holds the currently selected option's value string.
49
- * For multiple selection, `values` holds `string[]`. On change, a composed
50
- * `'change'` event is fired.
48
+ * **Vinculación de valores (Value binding):**
49
+ * La propiedad `value` contiene la cadena de valor de la opción actualmente seleccionada.
50
+ * Para selección múltiple, `values` contiene `string[]`. Al cambiar, se dispara un
51
+ * evento compuesto `'moni-change'`.
51
52
  *
52
- * @fires change - Bubbles and is composed. Fired when the selected value changes.
53
- * Read `element.value` (or `element.values` for `multiple`).
53
+ * @fires moni-change - Burbujea y está compuesto. Se dispara cuando el valor seleccionado cambia.
54
+ * Lee `element.value` (o `element.values` para `multiple`).
54
55
  *
55
56
  * @example
56
57
  * ```html
57
- * <moni-select label="Country" name="country" variant="outlined">
58
- * <moni-select-option value="us">United States</moni-select-option>
59
- * <moni-select-option value="gb">United Kingdom</moni-select-option>
60
- * <moni-select-option value="de">Germany</moni-select-option>
58
+ * <moni-select label="País" name="country" variant="outlined">
59
+ * <moni-select-option value="us">Estados Unidos</moni-select-option>
60
+ * <moni-select-option value="gb">Reino Unido</moni-select-option>
61
+ * <moni-select-option value="de">Alemania</moni-select-option>
61
62
  * </moni-select>
62
63
  *
63
- * <!-- Searchable select -->
64
- * <moni-select label="Language" searchable>
64
+ * <!-- Select con búsqueda -->
65
+ * <moni-select label="Idioma" searchable>
65
66
  * <moni-select-option value="ts">TypeScript</moni-select-option>
66
67
  * <moni-select-option value="py">Python</moni-select-option>
67
68
  * </moni-select>
68
69
  * ```
69
70
  *
70
- * @slot default - `<moni-select-option>` or `<moni-select-group>` children.
71
+ * @slot default - Hijos `<moni-select-option>` o `<moni-select-group>`.
71
72
  *
72
- * @csspart field - The outer `.field` div container.
73
- * @csspart dropdown - The floating option list container.
73
+ * @csspart field - El contenedor div exterior `.field`.
74
+ * @csspart dropdown - El contenedor flotante de la lista de opciones.
74
75
  */
75
76
  let MoniSelect = class MoniSelect extends MoniElement {
77
+ static { this.formAssociated = true; }
76
78
  constructor() {
77
- super(...arguments);
79
+ super();
80
+ /**
81
+ * Nombre del campo select, usado para el envío del formulario.
82
+ * @type {string}
83
+ */
78
84
  this.name = '';
85
+ /**
86
+ * Texto de la etiqueta flotante.
87
+ * @type {string}
88
+ */
79
89
  this.label = '';
90
+ /**
91
+ * Variante visual del campo select.
92
+ * @type {'filled' | 'outlined'}
93
+ * @default 'filled'
94
+ */
80
95
  this.variant = 'filled';
96
+ /**
97
+ * Define las dimensiones del campo select.
98
+ * @type {'small' | 'medium' | 'large' | 'extra'}
99
+ * @default 'medium'
100
+ */
81
101
  this.size = 'medium';
102
+ /**
103
+ * Forma (radio de borde) del campo.
104
+ * @type {'round' | 'square' | 'no-round'}
105
+ * @default 'no-round'
106
+ */
82
107
  this.shape = 'no-round';
108
+ /**
109
+ * Deshabilita el campo select.
110
+ * @type {boolean}
111
+ */
83
112
  this.disabled = false;
113
+ /**
114
+ * Si es verdadero, muestra un indicador de carga (progreso lineal).
115
+ * @type {boolean}
116
+ */
84
117
  this.loading = false;
118
+ /**
119
+ * Texto de ayuda mostrado debajo del campo.
120
+ * @type {string}
121
+ */
85
122
  this.helper = '';
123
+ /**
124
+ * Texto de error mostrado debajo del campo cuando `error` es true.
125
+ * Reemplaza al texto de ayuda.
126
+ * @type {string}
127
+ */
86
128
  this.errorText = '';
129
+ /**
130
+ * Si es verdadero, establece el campo en un estado de error.
131
+ * @type {boolean}
132
+ */
87
133
  this.error = false;
134
+ /**
135
+ * El valor actual del select.
136
+ * @type {string}
137
+ */
88
138
  this.value = '';
139
+ /**
140
+ * Nombre del icono principal (leading icon, Material Symbols).
141
+ * @type {string}
142
+ */
89
143
  this.icon = '';
144
+ /**
145
+ * Nombre del icono final (trailing icon, Material Symbols) que indica el estado del menú desplegable.
146
+ * @type {string}
147
+ * @default 'arrow_drop_down'
148
+ */
90
149
  this.trailingIcon = 'arrow_drop_down';
150
+ /**
151
+ * Habilita un campo de búsqueda en la parte superior del menú desplegable para filtrar opciones.
152
+ * @type {boolean}
153
+ */
91
154
  this.searchable = false;
155
+ /**
156
+ * Muestra un botón de limpieza cuando se selecciona un valor para restablecer fácilmente el campo.
157
+ * @type {boolean}
158
+ */
92
159
  this.clearable = false;
160
+ /**
161
+ * Renderiza las opciones como una hoja inferior (bottom sheet, ideal para dispositivos móviles) en lugar de un menú desplegable.
162
+ * @type {boolean}
163
+ */
93
164
  this.sheet = false;
165
+ /**
166
+ * Texto de marcador de posición (placeholder) mostrado cuando no hay ningún valor seleccionado.
167
+ * @type {string}
168
+ */
94
169
  this.placeholder = '';
170
+ /**
171
+ * Estrategia de posicionamiento para el menú desplegable.
172
+ * @type {'absolute' | 'fixed'}
173
+ * @default 'absolute'
174
+ */
95
175
  this.positioning = 'absolute';
176
+ /**
177
+ * Ubicación preferida del menú desplegable con respecto al disparador (trigger).
178
+ * @type {'top' | 'bottom' | 'left' | 'right' | 'auto'}
179
+ * @default 'auto'
180
+ */
96
181
  this.placement = 'auto';
182
+ /**
183
+ * Restricción de ancho del menú desplegable.
184
+ * - `'trigger'`: Coincide con el ancho del campo de entrada.
185
+ * - `'auto'`: Coincide con el ancho del contenido del menú desplegable.
186
+ * - O cualquier valor CSS de ancho válido (ej. '200px').
187
+ * @type {string}
188
+ * @default 'trigger'
189
+ */
97
190
  this.dropdownWidth = 'trigger';
98
191
  this._open = false;
99
192
  this._searchQuery = '';
@@ -103,23 +196,39 @@ let MoniSelect = class MoniSelect extends MoniElement {
103
196
  this._menuStyle = '';
104
197
  this._useInlineCategories = false;
105
198
  this._drilldownPath = [];
199
+ /**
200
+ * Cierra el Dropdown cuando el usuario hace clic fuera de las dimensiones del componente.
201
+ * Utiliza `e.composedPath()` para poder atravesar barreras de Shadow DOM si el select
202
+ * está dentro de un contenedor web-component externo.
203
+ */
106
204
  this._handleOutsideClick = (e) => {
107
205
  if (this._open && !e.composedPath().includes(this)) {
108
206
  this._closeDropdown();
109
207
  }
110
208
  };
209
+ /**
210
+ * Handler de Scroll global.
211
+ * Fuerza un recálculo de la posición y dimensiones del dropdown si el usuario
212
+ * hace scroll en la página mientras el select permanece abierto.
213
+ */
111
214
  this._handleScroll = () => {
112
215
  if (this._open) {
113
216
  this._determineActualPlacement();
114
217
  this._updateMenuPosition();
115
218
  }
116
219
  };
220
+ /**
221
+ * Handler de Resize global.
222
+ * Asegura que el popover del select no quede fuera del viewport cuando
223
+ * se cambia el tamaño de la ventana o se rota la pantalla en dispositivos móviles.
224
+ */
117
225
  this._handleResize = () => {
118
226
  if (this._open) {
119
227
  this._determineActualPlacement();
120
228
  this._updateMenuPosition();
121
229
  }
122
230
  };
231
+ this._internals = this.attachInternals();
123
232
  }
124
233
  static { this.styles = [
125
234
  sharedStyles,
@@ -445,20 +554,40 @@ let MoniSelect = class MoniSelect extends MoniElement {
445
554
  }
446
555
  `
447
556
  ]; }
557
+ /**
558
+ * Hook del ciclo de vida (Lit).
559
+ * Vincula event listeners globales necesarios para la lógica del dropdown.
560
+ * Se usa `capture: true` en el evento de scroll para poder reaccionar
561
+ * al desplazamiento de cualquier contenedor padre y reposicionar el menú a tiempo.
562
+ */
448
563
  connectedCallback() {
449
564
  super.connectedCallback();
450
565
  document.addEventListener('click', this._handleOutsideClick);
451
566
  window.addEventListener('scroll', this._handleScroll, { capture: true });
452
567
  window.addEventListener('resize', this._handleResize);
453
568
  }
569
+ /**
570
+ * Hook del ciclo de vida (Lit).
571
+ * Desmonta rigurosamente todos los listeners globales para prevenir memory leaks
572
+ * o llamadas accidentales cuando el select ya fue destruido del DOM.
573
+ */
454
574
  disconnectedCallback() {
455
575
  super.disconnectedCallback();
456
576
  document.removeEventListener('click', this._handleOutsideClick);
457
577
  window.removeEventListener('scroll', this._handleScroll, { capture: true });
458
578
  window.removeEventListener('resize', this._handleResize);
459
579
  }
580
+ /**
581
+ * Hook de actualización reactiva (Lit).
582
+ * Verifica si alguna propiedad relacionada con el tamaño del contenido (como la búsqueda,
583
+ * la ruta de anidación o el estado abierto) ha cambiado, para forzar un recálculo
584
+ * de la altura animada del contenedor `drilldown-wrapper`.
585
+ */
460
586
  updated(changedProperties) {
461
587
  super.updated(changedProperties);
588
+ if (changedProperties.has('value')) {
589
+ this._internals?.setFormValue?.(this.value);
590
+ }
462
591
  if (changedProperties.has('_open') ||
463
592
  changedProperties.has('_drilldownPath') ||
464
593
  changedProperties.has('_searchQuery') ||
@@ -467,6 +596,12 @@ let MoniSelect = class MoniSelect extends MoniElement {
467
596
  this._updateWrapperHeight();
468
597
  }
469
598
  }
599
+ /**
600
+ * Lógica de animación de altura (Height Animation).
601
+ * Cuando se navega entre categorías anidadas (`_drilldownPath`), las listas hijas pueden
602
+ * tener diferentes tamaños. Este método lee el `scrollHeight` del panel activo y lo aplica
603
+ * imperativamente al `wrapper` para disparar una transición CSS suave en la altura del dropdown.
604
+ */
470
605
  _updateWrapperHeight() {
471
606
  const wrapper = this.shadowRoot?.querySelector('.drilldown-wrapper');
472
607
  if (!wrapper)
@@ -486,6 +621,17 @@ let MoniSelect = class MoniSelect extends MoniElement {
486
621
  }
487
622
  });
488
623
  }
624
+ /**
625
+ * Motor de Cálculo de Colisiones de la Interfaz (Collision Detection).
626
+ *
627
+ * @logic
628
+ * 1. Calcula las coordenadas espaciales (`getBoundingClientRect`) del select base.
629
+ * 2. Compara el espacio disponible (`spaceAbove`, `spaceBelow`, `spaceRight`, `spaceLeft`)
630
+ * respecto al viewport (`window.innerHeight`, `window.innerWidth`).
631
+ * 3. Si el dropdown no cabe en la posición preferida (`placement`), revierte lógicamente
632
+ * la posición (ej: si `bottom` desborda, lo abre hacia `top`).
633
+ * 4. Actualiza `_actualPlacement` con la dirección segura calculada.
634
+ */
489
635
  _determineActualPlacement() {
490
636
  if (this.sheet) {
491
637
  this._actualPlacement = 'bottom';
@@ -537,6 +683,12 @@ let MoniSelect = class MoniSelect extends MoniElement {
537
683
  }
538
684
  }
539
685
  }
686
+ /**
687
+ * Aplica las coordenadas y dimensiones absolutas o fijas al menú desplegable.
688
+ * Este método es fundamental cuando `positioning === 'fixed'`, ya que el dropdown
689
+ * se saca del flujo normal del documento para evitar `overflow: hidden` de los padres.
690
+ * Mapea el `width` para coincidir opcionalmente con el gatillo (`dropdownWidth="trigger"`).
691
+ */
540
692
  _updateMenuPosition() {
541
693
  if (!this._open || this.sheet)
542
694
  return;
@@ -595,6 +747,12 @@ let MoniSelect = class MoniSelect extends MoniElement {
595
747
  `;
596
748
  }
597
749
  }
750
+ /**
751
+ * Devuelve un string de estilos inline para el menú desplegable.
752
+ * Si la posición es `fixed` (calculada dinámicamente para evadir overflow),
753
+ * retorna el bloque de coordenadas generado por `_updateMenuPosition`.
754
+ * Si no, asigna anchos basados en la propiedad `dropdownWidth` (auto, trigger, custom).
755
+ */
598
756
  _getMenuStyle() {
599
757
  if (this.positioning === 'fixed') {
600
758
  return this._menuStyle;
@@ -607,6 +765,18 @@ let MoniSelect = class MoniSelect extends MoniElement {
607
765
  }
608
766
  return '';
609
767
  }
768
+ /**
769
+ * Parseador del Shadow DOM (Slot Change Handler).
770
+ *
771
+ * @logic
772
+ * 1. Cuando los hijos proyectados cambian (ej. se agregan nuevos `<option>`),
773
+ * lee iterativamente todos los nodos del Light DOM.
774
+ * 2. Si encuentra `<optgroup>` o `<moni-select-option group="A/B">`, construye dinámicamente
775
+ * un árbol estructural de `GroupNode` anidados.
776
+ * 3. Si encuentra opciones, las inyecta en el grupo correspondiente del árbol.
777
+ * 4. Almacena el árbol resultante en `_parsedOptions` para que el componente
778
+ * pueda renderizar sus propios submenús nativos independientemente del markup inicial.
779
+ */
610
780
  _onSlotChange() {
611
781
  if (!this._slot)
612
782
  return;
@@ -656,6 +826,10 @@ let MoniSelect = class MoniSelect extends MoniElement {
656
826
  this._parsedOptions = tree;
657
827
  this.requestUpdate();
658
828
  }
829
+ /**
830
+ * Alterna el estado de apertura/cierre del dropdown, previniendo
831
+ * la acción si el componente está deshabilitado.
832
+ */
659
833
  _toggleDropdown(e) {
660
834
  if (e) {
661
835
  e.stopPropagation();
@@ -669,6 +843,11 @@ let MoniSelect = class MoniSelect extends MoniElement {
669
843
  this._openDropdown();
670
844
  }
671
845
  }
846
+ /**
847
+ * Manejador de clics en el campo de texto (Trigger).
848
+ * Si el componente es `searchable` (permite escribir para buscar), un clic
849
+ * sólo abrirá el menú (no lo cerrará si ya estaba abierto, para permitir al usuario seguir escribiendo).
850
+ */
672
851
  _onInputClick(e) {
673
852
  if (this.disabled)
674
853
  return;
@@ -681,28 +860,39 @@ let MoniSelect = class MoniSelect extends MoniElement {
681
860
  this._toggleDropdown(e);
682
861
  }
683
862
  }
863
+ /**
864
+ * Despliega el menú del select y coordina la accesibilidad, posicionamiento y foco inicial.
865
+ */
684
866
  _openDropdown() {
685
867
  this._open = true;
686
868
  this._activeIndex = -1;
687
869
  this._drilldownPath = [];
870
+ // Calculamos la dirección del menú emergente en base al espacio disponible en la pantalla
688
871
  this._determineActualPlacement();
689
- // Measure viewport to determine if we should fall back to inline categories
872
+ // Medimos dinámicamente si hay espacio suficiente para renderizar submenús laterales (Desktop).
873
+ // Si es móvil (<600px) o no hay 160px de espacio libre a los lados, forzamos un diseño plano ("inline categories")
874
+ // para evitar que los submenús se salgan del viewport.
690
875
  const rect = this.getBoundingClientRect();
691
876
  const spaceOnRight = window.innerWidth - rect.right;
692
877
  const spaceOnLeft = rect.left;
693
878
  this._useInlineCategories = window.innerWidth < 600 || (spaceOnRight < 160 && spaceOnLeft < 160);
879
+ // Si el menú tiene position="fixed", necesitamos computar y aplicar las coordenadas absolutas en pixels
694
880
  if (this.positioning === 'fixed') {
695
881
  this._updateMenuPosition();
696
882
  }
883
+ // Lógica especial si el componente está configurado como "searchable" (Input filtrable)
697
884
  if (this.searchable) {
698
885
  const selectedOpt = this._findOptionByValue(this.value);
699
886
  this._searchQuery = selectedOpt ? selectedOpt.label : '';
887
+ // Esperamos un tick para que el input o bottom-sheet sea renderizado antes de solicitar el foco
700
888
  setTimeout(() => {
701
889
  if (this._input && !this.sheet) {
890
+ // Foco en el input principal (Desktop) y seleccionamos todo el texto para fácil reemplazo
702
891
  this._input.focus();
703
892
  this._input.select();
704
893
  }
705
894
  else if (this.sheet) {
895
+ // Foco en la caja de búsqueda inyectada dentro del bottom-sheet (Mobile)
706
896
  const sheetInput = this.shadowRoot?.querySelector('.sheet-search-input');
707
897
  if (sheetInput) {
708
898
  sheetInput.focus();
@@ -712,6 +902,10 @@ let MoniSelect = class MoniSelect extends MoniElement {
712
902
  }, 50);
713
903
  }
714
904
  }
905
+ /**
906
+ * Cierra el dropdown y purga la consulta de búsqueda (`_searchQuery`)
907
+ * para que la próxima vez que se abra, la lista muestre todas las opciones por defecto.
908
+ */
715
909
  _closeDropdown() {
716
910
  this._open = false;
717
911
  this._searchQuery = '';
@@ -720,6 +914,15 @@ let MoniSelect = class MoniSelect extends MoniElement {
720
914
  _findOptionByValue(value) {
721
915
  return this._getFlatOptions(this._parsedOptions).find(opt => opt.value === value);
722
916
  }
917
+ /**
918
+ * Evento de input (tecleo) en la barra de búsqueda.
919
+ *
920
+ * @logic
921
+ * 1. Actualiza `_searchQuery` y fuerza la apertura del dropdown.
922
+ * 2. Si es `clearable` y el usuario borró todo, emite eventos vacíos.
923
+ * 3. Busca coincidencias exactas en el texto. Si el usuario teclea exactamente el
924
+ * label de una opción existente, la selecciona automáticamente (auto-completado nativo).
925
+ */
723
926
  _onSearchInput(e) {
724
927
  const query = e.target.value;
725
928
  this._searchQuery = query;
@@ -727,8 +930,7 @@ let MoniSelect = class MoniSelect extends MoniElement {
727
930
  this._activeIndex = -1;
728
931
  if (this.clearable && query.trim() === '') {
729
932
  this.value = '';
730
- this.dispatchEvent(new Event('input', { bubbles: true, composed: true }));
731
- this.dispatchEvent(new Event('change', { bubbles: true, composed: true }));
933
+ emitMoniEvent(this, 'moni-change', { detail: { value: this.value, originalEvent: e } });
732
934
  return;
733
935
  }
734
936
  const flat = this._getFlatOptions(this._parsedOptions);
@@ -737,6 +939,11 @@ let MoniSelect = class MoniSelect extends MoniElement {
737
939
  this._selectOption(exactMatch);
738
940
  }
739
941
  }
942
+ /**
943
+ * Confirma la selección de una opción específica.
944
+ * Actualiza el valor (estado reactivo), cierra el dropdown y despacha los eventos
945
+ * estándar HTML `input` y `change` para integrarse fluidamente con formularios nativos o frameworks.
946
+ */
740
947
  _selectOption(option) {
741
948
  if (option.disabled)
742
949
  return;
@@ -744,7 +951,14 @@ let MoniSelect = class MoniSelect extends MoniElement {
744
951
  this._closeDropdown();
745
952
  this.dispatchEvent(new Event('input', { bubbles: true, composed: true }));
746
953
  this.dispatchEvent(new Event('change', { bubbles: true, composed: true }));
954
+ emitMoniEvent(this, 'moni-change', { detail: { value: this.value } });
747
955
  }
956
+ /**
957
+ * Maneja el Hover sobre categorías en modo Desktop (Submenús emergentes).
958
+ * Detecta dinámicamente si el submenú se saldrá del lado derecho de la pantalla.
959
+ * Si es así, altera las clases de CSS (`open-left` vs `open-right`) para que
960
+ * el menú flote en la dirección opuesta, evitando desbordamientos de viewport (Overflow prevention).
961
+ */
748
962
  _onSubmenuMouseEnter(e) {
749
963
  const headerEl = e.currentTarget;
750
964
  const submenu = headerEl.querySelector(':scope > .submenu');
@@ -763,16 +977,23 @@ let MoniSelect = class MoniSelect extends MoniElement {
763
977
  submenu.classList.add('open-right');
764
978
  }
765
979
  }
980
+ /**
981
+ * Gestiona la navegación completa por teclado siguiendo el patrón WAI-ARIA Combobox.
982
+ * Soporta flechas direccionales, selección (Enter), y cierre (Escape).
983
+ */
766
984
  _onKeyDown(e) {
767
985
  if (this.disabled)
768
986
  return;
987
+ // Obtenemos solo las opciones que están visualmente disponibles en la jerarquía actual
769
988
  const visible = this._getVisibleOptions();
770
989
  if (e.key === 'ArrowDown') {
771
990
  e.preventDefault();
772
991
  if (!this._open) {
992
+ // Si está cerrado, ArrowDown lo abre (comportamiento estándar nativo)
773
993
  this._openDropdown();
774
994
  }
775
995
  else if (visible.length > 0) {
996
+ // Navegamos circularmente hacia abajo
776
997
  this._activeIndex = (this._activeIndex + 1) % visible.length;
777
998
  this._scrollToActive();
778
999
  }
@@ -780,6 +1001,7 @@ let MoniSelect = class MoniSelect extends MoniElement {
780
1001
  else if (e.key === 'ArrowUp') {
781
1002
  e.preventDefault();
782
1003
  if (this._open && visible.length > 0) {
1004
+ // Navegamos circularmente hacia arriba (+visible.length evita valores negativos en JS)
783
1005
  this._activeIndex = (this._activeIndex - 1 + visible.length) % visible.length;
784
1006
  this._scrollToActive();
785
1007
  }
@@ -787,20 +1009,27 @@ let MoniSelect = class MoniSelect extends MoniElement {
787
1009
  else if (e.key === 'Enter') {
788
1010
  e.preventDefault();
789
1011
  if (this._open) {
1012
+ // Si está abierto y hay una opción resaltada, simulamos el click para seleccionarla
790
1013
  if (this._activeIndex >= 0 && this._activeIndex < visible.length) {
791
1014
  this._selectOption(visible[this._activeIndex]);
792
1015
  }
793
1016
  }
794
1017
  else {
1018
+ // Enter cuando está cerrado simplemente abre el menú
795
1019
  this._openDropdown();
796
1020
  }
797
1021
  }
798
1022
  else if (e.key === 'Escape') {
799
1023
  e.preventDefault();
1024
+ // Escapa el menú sin hacer ninguna selección
800
1025
  this._closeDropdown();
801
1026
  }
802
1027
  }
1028
+ /**
1029
+ * Asegura que el elemento resaltado por teclado sea visible dentro del contenedor scrolleable.
1030
+ */
803
1031
  _scrollToActive() {
1032
+ // Se requiere setTimeout para darle tiempo a Lit a renderizar la clase 'active-nav'
804
1033
  setTimeout(() => {
805
1034
  const activeEl = this.shadowRoot?.querySelector('.option-item.active-nav');
806
1035
  if (activeEl) {
@@ -808,6 +1037,10 @@ let MoniSelect = class MoniSelect extends MoniElement {
808
1037
  }
809
1038
  }, 0);
810
1039
  }
1040
+ /**
1041
+ * Aplana el árbol jerárquico recursivo de <moni-select-group> a un array unidimensional de opciones puras.
1042
+ * Esencial para que la búsqueda por texto funcione globalmente ignorando las categorías.
1043
+ */
811
1044
  _getFlatOptions(nodes) {
812
1045
  const flat = [];
813
1046
  const traverse = (n) => {
@@ -841,6 +1074,13 @@ let MoniSelect = class MoniSelect extends MoniElement {
841
1074
  }
842
1075
  return filtered;
843
1076
  }
1077
+ /**
1078
+ * Motor de Renderizado: Lista Raíz (Modo Móvil / Drilldown).
1079
+ *
1080
+ * Renderiza las opciones iniciales y los grupos base de la categoría actual (`_drilldownPath`).
1081
+ * Asigna clases dinámicas (`selected`, `active-nav`) para la retroalimentación visual
1082
+ * del teclado y el valor actualmente seleccionado.
1083
+ */
844
1084
  _renderRootList() {
845
1085
  let visibleIndex = 0;
846
1086
  return this._parsedOptions.map(node => {
@@ -865,6 +1105,13 @@ let MoniSelect = class MoniSelect extends MoniElement {
865
1105
  `;
866
1106
  });
867
1107
  }
1108
+ /**
1109
+ * Motor de Renderizado: Subcategorías (Modo Móvil / Drilldown).
1110
+ *
1111
+ * A diferencia de desktop (donde los submenús flotan a los lados), en dispositivos
1112
+ * móviles o espacios constreñidos, el menú transiciona in-situ. Este método renderiza
1113
+ * el header del grupo activo, un botón de "Regresar" (Arrow Back) y las opciones hijas.
1114
+ */
868
1115
  _renderSubcategoryList() {
869
1116
  if (this._drilldownPath.length === 0)
870
1117
  return nothing;
@@ -928,6 +1175,14 @@ let MoniSelect = class MoniSelect extends MoniElement {
928
1175
  </li>
929
1176
  `;
930
1177
  }
1178
+ /**
1179
+ * Orquestador principal de renderizado de la lista de opciones.
1180
+ *
1181
+ * Si el usuario introdujo texto (`_searchQuery`), renderiza los resultados filtrados.
1182
+ * Si la lista original está vacía, muestra un mensaje amigable (Empty State).
1183
+ * Determina condicionalmente si usar el modo plano/Drilldown (Móviles) o
1184
+ * el modo Desktop con submenús flotantes (`_renderDesktopNode`).
1185
+ */
931
1186
  _renderOptionsList(filtered) {
932
1187
  if (this._parsedOptions.length === 0) {
933
1188
  return html `<li class="no-options">No options found</li>`;
@@ -977,6 +1232,35 @@ let MoniSelect = class MoniSelect extends MoniElement {
977
1232
  const flatIndexRef = { value: 0 };
978
1233
  return this._parsedOptions.map(node => this._renderDesktopNode(node, flatIndexRef));
979
1234
  }
1235
+ /**
1236
+ * Ensambla el Shadow DOM del campo select, coordinando dos modos de interfaz de usuario distintos.
1237
+ *
1238
+ * **Resolución del valor a mostrar (Display value):**
1239
+ * El contenido de texto visible en el input está determinado por prioridad:
1240
+ * 1. Mientras el menú desplegable está abierto Y `searchable=true` Y NO es modo sheet:
1241
+ * muestra `_searchQuery` (el texto del filtro en vivo que el usuario está escribiendo).
1242
+ * 2. De lo contrario: muestra `selectedOpt.label` (la etiqueta de la opción actualmente
1243
+ * seleccionada) o vuelve a la cadena vacía.
1244
+ *
1245
+ * **Dos rutas de renderizado:**
1246
+ * - **Modo Sheet (`sheet=true`):** Renderiza un `<moni-bottom-sheet>` como un
1247
+ * cajón (drawer) superpuesto a pantalla completa, ideal para IU táctiles móviles. La lista de opciones
1248
+ * se renderiza dentro de la hoja en lugar del menú desplegable.
1249
+ * - **Modo desplegable (por defecto):** Renderiza un `.dropdown-menu` flotante que
1250
+ * se abre debajo o arriba del campo. La cadena `_menuStyle` (calculada por
1251
+ * `_computeMenuStyle()`) inyecta los `top`, `left`, `width`, y
1252
+ * sobreescrituras `position: fixed` correctas para contenedores con scroll (scroll-contained) y parents con overflow cortado (overflow-clipping).
1253
+ *
1254
+ * **Patrón combobox ARIA:**
1255
+ * El input de texto lleva `role="combobox"`, `aria-haspopup="listbox"` y
1256
+ * `aria-expanded` para satisfacer los requisitos del combobox WCAG 2.1 para lectores de pantalla.
1257
+ * `aria-activedescendant` se establece al ID de la opción actualmente enfocada por teclado
1258
+ * para habilitar el movimiento del cursor virtual sin gestión del foco.
1259
+ *
1260
+ * **Composición de `fieldClasses`:**
1261
+ * Sigue la convención de nomenclatura de clases de estilos de campo de BeerCSS. `prefix` se agrega
1262
+ * cuando `icon` está establecido (para desplazar el relleno -padding- inline-start del input de texto para el icono).
1263
+ */
980
1264
  render() {
981
1265
  const hasLeading = Boolean(this.icon);
982
1266
  const filtered = this._getFilteredOptions();