@moni-labs/moni-ui 0.3.1 → 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 +5181 -1043
  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 +471 -53
  31. package/dist/components/moni-carousel.d.ts.map +1 -1
  32. package/dist/components/moni-carousel.js +862 -264
  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 +953 -290
  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
@@ -8,39 +8,40 @@
8
8
  import { html, css } from 'lit';
9
9
  import { customElement, property, query } from 'lit/decorators.js';
10
10
  import { MoniElement, sharedStyles } from './_base/index.js';
11
+ import { emitMoniEvent } from '../utils/event-emitter.js';
11
12
 
12
13
  /**
13
- * Material Design 3 Bottom Sheet component.
14
+ * Componente Material Design 3 Bottom Sheet.
14
15
  *
15
- * Bottom sheets are surfaces anchored to the bottom of the screen that
16
- * supplement the main view. They display supplementary content, contextual
17
- * actions, or task flows without fully obscuring the primary content.
16
+ * Los bottom sheets son superficies ancladas a la parte inferior de la pantalla que
17
+ * complementan la vista principal. Muestran contenido complementario, acciones
18
+ * contextuales, o flujos de tareas sin ocultar por completo el contenido principal.
18
19
  *
19
- * **M3 spec reference:** `m3-docs/components/sheets-bottom/specs.md`
20
+ * **Referencia de la especificación M3:** `m3-docs/components/sheets-bottom/specs.md`
20
21
  *
21
- * **Implementation notenative `<dialog>` element:**
22
- * Like `<moni-dialog>`, this component wraps the native `<dialog>` element.
23
- * The `open` property drives `dialog.showModal()` / `dialog.close()`. When
24
- * `modal=true` (default), a `::backdrop` scrim is rendered automatically.
22
+ * **Nota de implementación elemento nativo `<dialog>`:**
23
+ * Al igual que `<moni-dialog>`, este componente envuelve el elemento nativo `<dialog>`.
24
+ * La propiedad `open` controla `dialog.showModal()` / `dialog.close()`. Cuando
25
+ * `modal=true` (por defecto), se renderiza automáticamente un fondo `::backdrop`.
25
26
  *
26
- * **Teleportation (body-level mounting):**
27
- * When `positioning="body"` (default), the component moves itself to
28
- * `document.body` on `connectedCallback` so the fixed-bottom dialog renders
29
- * above all stacking contexts. On `disconnectedCallback`, it is moved back
30
- * to its original DOM position. This avoids clipping by `overflow: hidden`
31
- * or `transform` ancestors.
27
+ * **Teletransportación (montaje a nivel del body):**
28
+ * Cuando `positioning="body"` (por defecto), el componente se mueve a
29
+ * `document.body` en `connectedCallback` para que el diálogo inferior fijo se renderice
30
+ * por encima de todos los contextos de apilamiento. En `disconnectedCallback`, se mueve de nuevo
31
+ * a su posición original en el DOM. Esto evita el recorte por un ancestro con `overflow: hidden`
32
+ * o `transform`.
32
33
  *
33
- * **Sizes:**
34
- * - `small` — Compact sheet; suitable for simple action menus.
35
- * - `medium` — Standard height (default).
36
- * - `large` — Expanded height (`expandedHeight` controls the max block-size).
37
- * - `auto` — Content-driven height.
34
+ * **Tamaños:**
35
+ * - `small` — Hoja compacta; adecuada para menús de acciones simples.
36
+ * - `medium` — Altura estándar (por defecto).
37
+ * - `large` — Altura expandida (`expandedHeight` controla el block-size máximo).
38
+ * - `auto` — Altura impulsada por el contenido.
38
39
  *
39
40
  * @example
40
41
  * ```html
41
- * <moni-bottom-sheet title="Share">
42
- * <moni-list-item icon="share">Copy link</moni-list-item>
43
- * <moni-list-item icon="mail">Send via email</moni-list-item>
42
+ * <moni-bottom-sheet title="Compartir">
43
+ * <moni-list-item icon="share">Copiar enlace</moni-list-item>
44
+ * <moni-list-item icon="mail">Enviar por correo</moni-list-item>
44
45
  * </moni-bottom-sheet>
45
46
  *
46
47
  * <script>
@@ -48,34 +49,34 @@ import { MoniElement, sharedStyles } from './_base/index.js';
48
49
  * </script>
49
50
  * ```
50
51
  *
51
- * @slot default - The body content of the bottom sheet.
52
- * @slot handle - The drag handle area at the top of the sheet.
53
- * @slot footer - Action buttons at the bottom of the sheet.
52
+ * @slot default - El contenido principal del bottom sheet.
53
+ * @slot handle - El área del asa de arrastre en la parte superior.
54
+ * @slot footer - Botones de acción en la parte inferior de la hoja.
54
55
  *
55
- * @csspart dialog - The native `<dialog>` element.
56
- * @csspart header - The header container with title and close button.
57
- * @csspart body - The scrollable body content area.
58
- * @csspart footer - The footer action buttons area.
56
+ * @csspart dialog - El elemento nativo `<dialog>`.
57
+ * @csspart header - El contenedor del encabezado con el título y el botón de cierre.
58
+ * @csspart body - El área de contenido principal desplazable (scrollable).
59
+ * @csspart footer - El área de los botones de acción en el pie.
59
60
  */
60
61
  @customElement('moni-bottom-sheet')
61
62
  export class MoniBottomSheet extends MoniElement {
62
63
  /**
63
- * Controls the open/closed state of the bottom sheet.
64
+ * Controla el estado abierto/cerrado del bottom sheet.
64
65
  *
65
- * When set to `true`, calls `dialog.showModal()` or `dialog.show()`
66
- * depending on the `modal` property. When set to `false`, calls `dialog.close()`.
66
+ * Cuando se establece en `true`, llama a `dialog.showModal()` o `dialog.show()`
67
+ * dependiendo de la propiedad `modal`. Cuando se establece en `false`, llama a `dialog.close()`.
67
68
  *
68
69
  * @default false
69
70
  */
70
71
  @property({ type: Boolean, reflect: true }) open = false;
71
72
 
72
73
  /**
73
- * Height variant of the sheet container.
74
+ * Variante de altura del contenedor de la hoja.
74
75
  *
75
- * - `'small'` — Compact; suitable for quick confirmations.
76
- * - `'medium'` — Standard height (default).
77
- * - `'large'` — Fills `expandedHeight` of the viewport.
78
- * - `'auto'` — Content-driven; height adapts to the slotted content.
76
+ * - `'small'` — Compacta; adecuada para confirmaciones rápidas.
77
+ * - `'medium'` — Altura estándar (por defecto).
78
+ * - `'large'` — Llena el `expandedHeight` de la ventana gráfica.
79
+ * - `'auto'` — Depende del contenido; la altura se adapta al contenido en el slot.
79
80
  *
80
81
  * @default 'medium'
81
82
  */
@@ -83,28 +84,28 @@ export class MoniBottomSheet extends MoniElement {
83
84
  size: 'small' | 'medium' | 'large' | 'auto' = 'medium';
84
85
 
85
86
  /**
86
- * When `true` (default), the sheet opens as a modal dialog with a backdrop
87
- * scrim. When `false`, it opens as a non-modal overlay with no scrim.
87
+ * Cuando es `true` (por defecto), la hoja se abre como un diálogo modal con un
88
+ * fondo translúcido (scrim). Cuando es `false`, se abre como una superposición no modal sin scrim.
88
89
  *
89
90
  * @default true
90
91
  */
91
92
  @property({ type: Boolean, reflect: true }) modal = true;
92
93
 
93
94
  /**
94
- * Heading text displayed in the sheet's header area.
95
+ * Texto de encabezado mostrado en el área del encabezado de la hoja.
95
96
  *
96
97
  * @default ''
97
98
  */
98
99
  @property({ reflect: true }) title = '';
99
100
 
100
101
  /**
101
- * Controls how the sheet is positioned in the document.
102
+ * Controla cómo se posiciona la hoja en el documento.
102
103
  *
103
- * - `'body'` (default) — Teleports the element to `document.body` so
104
- * the fixed overlay renders above all stacking contexts.
105
- * - `'fixed'` — Fixed positioning within its current DOM subtree.
106
- * - `'absolute'` — Absolute within the nearest positioned ancestor.
107
- * - `'static'` — Static flow (rarely needed; for testing only).
104
+ * - `'body'` (por defecto) — Teletransporta el elemento a `document.body` para que
105
+ * la superposición fija se renderice por encima de todos los contextos de apilamiento.
106
+ * - `'fixed'` — Posicionamiento fijo dentro de su subárbol DOM actual.
107
+ * - `'absolute'` — Absoluto dentro del ancestro posicionado más cercano.
108
+ * - `'static'` — Flujo estático (rara vez necesario; solo para pruebas).
108
109
  *
109
110
  * @default 'fixed'
110
111
  */
@@ -112,11 +113,11 @@ export class MoniBottomSheet extends MoniElement {
112
113
  positioning: 'body' | 'fixed' | 'absolute' | 'static' = 'fixed';
113
114
 
114
115
  /**
115
- * Maximum block-size (height) of the sheet when `size="large"`.
116
+ * Block-size (altura) máximo de la hoja cuando `size="large"`.
116
117
  *
117
- * Accepts any valid CSS `max-block-size` value (e.g. `'85%'`, `'600px'`).
118
- * Defaults to `'85%'` which is the M3-recommended maximum for bottom sheets
119
- * on compact screens.
118
+ * Acepta cualquier valor válido de `max-block-size` en CSS (ej. `'85%'`, `'600px'`).
119
+ * Por defecto es `'85%'` que es el máximo recomendado por M3 para bottom sheets
120
+ * en pantallas compactas.
120
121
  *
121
122
  * @default '85%'
122
123
  */
@@ -124,30 +125,30 @@ export class MoniBottomSheet extends MoniElement {
124
125
  expandedHeight = '85%';
125
126
 
126
127
  /**
127
- * Optional maximum inline-size (width) constraint for the sheet.
128
+ * Restricción opcional de inline-size (ancho) máximo para la hoja.
128
129
  *
129
- * When set (e.g. `'640px'`), the sheet will not exceed this width even on
130
- * wide displays. Useful for tablet/desktop breakpoints where a centered
131
- * modal is preferred over a full-width sheet.
130
+ * Cuando se establece (ej. `'640px'`), la hoja no excederá este ancho incluso en
131
+ * pantallas anchas. Útil para puntos de interrupción de tableta/escritorio donde se prefiere
132
+ * un modal centrado en lugar de una hoja de ancho completo.
132
133
  *
133
- * @default '' (no constraint)
134
+ * @default '' (sin restricción)
134
135
  */
135
136
  @property({ reflect: true, attribute: 'max-width' })
136
137
  maxWidth = '';
137
138
 
138
139
  /**
139
- * Original parent node before teleportation to `document.body`.
140
- * Used to restore the element's DOM position in `disconnectedCallback`.
140
+ * Nodo padre original antes de la teletransportación a `document.body`.
141
+ * Utilizado para restaurar la posición DOM del elemento en `disconnectedCallback`.
141
142
  */
142
143
  private _originalParent: Node | null = null;
143
144
 
144
145
  /**
145
- * Original next sibling before teleportation to `document.body`.
146
- * Used alongside `_originalParent` to restore the exact DOM position.
146
+ * Hermano siguiente original antes de la teletransportación a `document.body`.
147
+ * Utilizado junto con `_originalParent` para restaurar la posición exacta en el DOM.
147
148
  */
148
149
  private _originalSibling: Node | null = null;
149
150
 
150
- /** Direct reference to the native `<dialog>` element. */
151
+ /** Referencia directa al elemento nativo `<dialog>`. */
151
152
  @query('dialog') private _dialog!: HTMLDialogElement;
152
153
  private _isDragging = false;
153
154
  private _startY = 0;
@@ -155,7 +156,61 @@ export class MoniBottomSheet extends MoniElement {
155
156
  private _sheetHeight = 0;
156
157
  private _defaultHeight = 0;
157
158
  private _justDragged = false;
159
+ private _skipRequestClose = false;
160
+
161
+ override willUpdate(changed: Map<string, unknown>) {
162
+ if (changed.has('open') && this.open !== changed.get('open')) {
163
+ const isOpening = this.open;
164
+ if (isOpening) {
165
+ const allowed = emitMoniEvent(this, 'moni-request-open', { cancelable: true });
166
+ if (!allowed) {
167
+ this.open = false;
168
+ }
169
+ } else if (!this._skipRequestClose) {
170
+ const allowed = emitMoniEvent(this, 'moni-request-close', { cancelable: true });
171
+ if (!allowed) {
172
+ this.open = true;
173
+ }
174
+ }
175
+ }
176
+ }
177
+
178
+ private async _animateAndClose() {
179
+ this._skipRequestClose = true;
180
+ const allowed = emitMoniEvent(this, 'moni-request-close', { cancelable: true });
181
+ this._skipRequestClose = false;
182
+ if (!allowed) return false;
183
+
184
+ this.dispatchEvent(new Event('close', { bubbles: true, composed: true }));
185
+ emitMoniEvent(this, 'moni-close');
186
+
187
+ this._dialog.classList.remove('expanded');
188
+ this._dialog.style.transform = 'translateY(100%)';
189
+ this._dialog.style.height = '';
190
+
191
+ await new Promise(resolve => {
192
+ const onEnd = () => {
193
+ this._dialog.removeEventListener('transitionend', onEnd);
194
+ resolve(null);
195
+ };
196
+ this._dialog.addEventListener('transitionend', onEnd);
197
+ setTimeout(onEnd, 300);
198
+ });
199
+
200
+ this._dialog.style.transform = '';
201
+ this._skipRequestClose = true;
202
+ this.open = false;
203
+ this._skipRequestClose = false;
204
+ emitMoniEvent(this, 'moni-closed');
205
+ return true;
206
+ }
158
207
 
208
+ /**
209
+ * Calcula la altura máxima permitida en píxeles basándose en la propiedad `expandedHeight`.
210
+ * Útil para la lógica de arrastre donde necesitamos valores numéricos absolutos (px) en
211
+ * lugar de porcentajes o unidades de viewport, asegurando que el bottom-sheet no exceda
212
+ * el tamaño permitido en pantalla.
213
+ */
159
214
  private _getMaxHeightPx(): number {
160
215
  const val = this.expandedHeight || '85%';
161
216
  if (val.endsWith('%')) {
@@ -170,51 +225,65 @@ export class MoniBottomSheet extends MoniElement {
170
225
  return window.innerHeight * 0.85;
171
226
  }
172
227
 
228
+ /**
229
+ * Inicia el proceso de arrastre (drag) cuando el usuario presiona sobre el `handle` o el `header`.
230
+ * Captura el puntero para asegurar que los eventos de movimiento se sigan recibiendo incluso si
231
+ * el cursor se sale de los límites físicos del elemento.
232
+ */
173
233
  private _onPointerDown(e: PointerEvent) {
174
234
  const target = e.target as HTMLElement;
235
+ // Solo iniciamos el arrastre si el click provino del asa superior (handle) o del encabezado.
175
236
  if (!target.closest('.handle') && !target.closest('header')) return;
176
237
 
177
238
  this._isDragging = true;
178
- this._startY = e.clientY;
179
- this._sheetHeight = this._dialog.getBoundingClientRect().height;
239
+ this._startY = e.clientY; // Almacenamos la coordenada inicial Y para calcular el delta luego
240
+ this._sheetHeight = this._dialog.getBoundingClientRect().height; // Capturamos la altura actual
180
241
  this._currentTranslationY = 0;
181
242
 
182
243
  const isExpanded = this._dialog.classList.contains('expanded');
244
+ // Si no estaba expandido previamente, guardamos su altura por defecto para usarla como punto de retorno.
183
245
  if (!isExpanded) {
184
246
  this._defaultHeight = this._sheetHeight;
185
247
  }
186
248
 
249
+ // setPointerCapture enruta todos los eventos subsecuentes a este target
187
250
  target.setPointerCapture(e.pointerId);
188
- this._dialog.classList.add('dragging');
251
+ this._dialog.classList.add('dragging'); // Desactiva las transiciones CSS para un seguimiento suave 1:1
189
252
  }
190
253
 
254
+ /**
255
+ * Maneja el movimiento del puntero mientras se arrastra el componente.
256
+ * Interpola la altura o la transformación Y dependiendo de si se está expandiendo o colapsando,
257
+ * y de su estado actual (expandido o normal).
258
+ */
191
259
  private _onPointerMove(e: PointerEvent) {
192
260
  if (!this._isDragging) return;
193
261
 
262
+ // Diferencia en píxeles desde donde se inició el click
194
263
  const deltaY = e.clientY - this._startY;
195
264
  const isExpanded = this._dialog.classList.contains('expanded');
196
265
  const maxHeight = this._getMaxHeightPx();
197
266
 
198
267
  if (isExpanded) {
199
268
  if (deltaY > 0) {
200
- // Dragging down from expanded: shrink height
269
+ // Arrastrando hacia abajo desde el estado expandido: reducimos su altura
201
270
  const newHeight = this._sheetHeight - deltaY;
202
271
  this._dialog.style.transform = '';
203
272
  this._dialog.style.height = `${Math.max(0, newHeight)}px`;
204
273
  } else {
205
- // Pulling up from expanded: resistance
206
- const newHeight = this._sheetHeight - deltaY * 0.2;
274
+ // Tirando hacia arriba cuando ya está expandido: aplicamos resistencia friccional
275
+ const newHeight = this._sheetHeight - deltaY * 0.2; // 0.2 simula tensión (rubber-band)
207
276
  this._dialog.style.transform = '';
208
277
  this._dialog.style.height = `${Math.min(maxHeight, newHeight)}px`;
209
278
  }
210
279
  } else {
211
280
  if (deltaY > 0) {
212
- // Dragging down from normal: translate down
281
+ // Arrastrando hacia abajo desde su estado inicial: lo empujamos visualmente hacia abajo (translate)
213
282
  this._currentTranslationY = deltaY;
214
283
  this._dialog.style.transform = `translateY(${deltaY}px)`;
215
284
  this._dialog.style.height = '';
216
285
  } else {
217
- // Dragging up from normal: grow height
286
+ // Arrastrando hacia arriba desde su estado inicial: hacemos que crezca su altura
218
287
  const newHeight = this._sheetHeight - deltaY;
219
288
  this._dialog.style.transform = '';
220
289
  this._dialog.style.height = `${Math.min(maxHeight, newHeight)}px`;
@@ -222,15 +291,21 @@ export class MoniBottomSheet extends MoniElement {
222
291
  }
223
292
  }
224
293
 
294
+ /**
295
+ * Finaliza la interacción de arrastre, evaluando si el bottom-sheet debe
296
+ * expandirse, regresar a su estado original o cerrarse completamente según la
297
+ * inercia o la distancia arrastrada.
298
+ */
225
299
  private _onPointerUp(e: PointerEvent) {
226
300
  if (!this._isDragging) return;
227
301
 
228
302
  const target = e.target as HTMLElement;
229
- target.releasePointerCapture(e.pointerId);
303
+ target.releasePointerCapture(e.pointerId); // Liberamos el control del puntero
230
304
  this._isDragging = false;
231
- this._dialog.classList.remove('dragging');
305
+ this._dialog.classList.remove('dragging'); // Reactivamos las transiciones CSS
232
306
 
233
307
  const deltaY = e.clientY - this._startY;
308
+ // Si se movió más de 5px, bloqueamos clics accidentales para evitar disparar eventos subyacentes
234
309
  if (Math.abs(deltaY) > 5) {
235
310
  this._justDragged = true;
236
311
  setTimeout(() => {
@@ -241,75 +316,58 @@ export class MoniBottomSheet extends MoniElement {
241
316
  const maxHeight = this._getMaxHeightPx();
242
317
 
243
318
  if (isExpanded) {
319
+ // Evaluamos la altura final tras soltar el ratón/dedo
244
320
  const finalHeight = this._sheetHeight - deltaY;
245
321
  if (finalHeight < this._defaultHeight - 80) {
246
- // Close completely
247
- this._dialog.classList.remove('expanded');
248
- this._dialog.style.transform = 'translateY(100%)';
249
- this._dialog.style.height = '';
250
-
251
- const onTransitionEnd = () => {
252
- this._dialog.removeEventListener('transitionend', onTransitionEnd);
253
- this._dialog.style.transform = '';
254
- this._dialog.style.height = '';
255
- this.open = false;
256
- this.dispatchEvent(new CustomEvent('close'));
257
- };
258
- this._dialog.addEventListener('transitionend', onTransitionEnd);
259
- setTimeout(() => {
260
- if (this.open) onTransitionEnd();
261
- }, 300);
322
+ // Si se arrastró significativamente por debajo de la altura por defecto, lo cerramos
323
+ this._animateAndClose().then((closed) => {
324
+ if (!closed) {
325
+ // Si se canceló el evento, regresamos a su lugar
326
+ this._dialog.style.transform = '';
327
+ this._dialog.style.height = '';
328
+ }
329
+ });
262
330
  } else if (finalHeight < (maxHeight + this._defaultHeight) / 2) {
263
- // Collapse back to normal height
331
+ // Si se soltó a medio camino, lo colapsamos a su altura normal
264
332
  this._dialog.classList.remove('expanded');
265
333
  this._dialog.style.transform = '';
266
334
  this._dialog.style.height = '';
267
335
  } else {
268
- // Snap back to expanded
336
+ // Si no se arrastró lo suficiente hacia abajo, retorna a estado expandido (snap back)
269
337
  this._dialog.style.transform = '';
270
338
  this._dialog.style.height = '';
271
339
  }
272
340
  } else {
273
341
  if (deltaY < 0) {
274
- // Dragged up
342
+ // Evaluamos el arrastre hacia arriba desde el estado colapsado
275
343
  const finalHeight = this._sheetHeight - deltaY;
276
- const threshold = (maxHeight + this._sheetHeight) / 2;
277
- if (finalHeight > threshold || -deltaY > 80) {
278
- // Snap to expanded
344
+ if (finalHeight > this._sheetHeight + 80) {
345
+ // Expandimos el bottom-sheet hasta la altura máxima
279
346
  this._dialog.classList.add('expanded');
280
- this._dialog.style.transform = '';
281
- this._dialog.style.height = '';
282
- } else {
283
- // Revert to normal
284
- this._dialog.style.transform = '';
285
- this._dialog.style.height = '';
286
347
  }
348
+ this._dialog.style.transform = '';
349
+ this._dialog.style.height = '';
287
350
  } else {
288
- // Dragged down
289
- const threshold = Math.min(150, this._sheetHeight * 0.4);
290
- if (this._currentTranslationY > threshold) {
291
- this._dialog.style.transform = 'translateY(100%)';
292
- this._dialog.style.height = '';
293
-
294
- const onTransitionEnd = () => {
295
- this._dialog.removeEventListener('transitionend', onTransitionEnd);
296
- this._dialog.style.transform = '';
297
- this._dialog.style.height = '';
298
- this.open = false;
299
- this.dispatchEvent(new CustomEvent('close'));
300
- };
301
- this._dialog.addEventListener('transitionend', onTransitionEnd);
302
- setTimeout(() => {
303
- if (this.open) onTransitionEnd();
304
- }, 300);
351
+ // Evaluamos el arrastre hacia abajo para cerrar el componente
352
+ if (this._currentTranslationY > 80) {
353
+ this._animateAndClose().then((closed) => {
354
+ if (!closed) {
355
+ this._dialog.style.transform = '';
356
+ }
357
+ });
305
358
  } else {
359
+ // Regresa a su estado colapsado (snap back al inicio)
306
360
  this._dialog.style.transform = '';
307
- this._dialog.style.height = '';
308
361
  }
309
362
  }
310
363
  }
311
364
  }
312
365
 
366
+ /**
367
+ * Aborta limpiamente la interacción de arrastre (Pointer Cancel).
368
+ * Se dispara cuando el SO interrumpe el touch (ej: entrada de una llamada)
369
+ * o si el navegador toma el control para un scroll nativo imprevisto.
370
+ */
313
371
  private _onPointerCancel(e: PointerEvent) {
314
372
  if (!this._isDragging) return;
315
373
 
@@ -321,6 +379,12 @@ export class MoniBottomSheet extends MoniElement {
321
379
  this._dialog.style.height = '';
322
380
  }
323
381
 
382
+ /**
383
+ * Handler de clicks en la superficie del modal (Backdrop).
384
+ * Si el clic cae exactamente en el fondo (`this._dialog`) y no en el contenedor de
385
+ * contenido interno (`this._sheetContent`), y si el sheet acaba de ser arrastrado
386
+ * sin soltar, ignora el click. De lo contrario, cierra fluidamente el modal deslizando hacia abajo.
387
+ */
324
388
  private _onDialogClick(e: MouseEvent) {
325
389
  if (this._justDragged) {
326
390
  this._justDragged = false;
@@ -330,22 +394,17 @@ export class MoniBottomSheet extends MoniElement {
330
394
  // Click on backdrop targets the dialog element itself. Clicks on children target the children.
331
395
  if (e.target !== this._dialog) return;
332
396
 
333
- this._dialog.style.transform = 'translateY(100%)';
334
- this._dialog.style.height = '';
335
-
336
- const onTransitionEnd = () => {
337
- this._dialog.removeEventListener('transitionend', onTransitionEnd);
338
- this._dialog.style.transform = '';
339
- this._dialog.style.height = '';
340
- this.open = false;
341
- this.dispatchEvent(new CustomEvent('close'));
342
- };
343
- this._dialog.addEventListener('transitionend', onTransitionEnd);
344
- setTimeout(() => {
345
- if (this.open) onTransitionEnd();
346
- }, 300);
397
+ this._animateAndClose();
347
398
  }
348
399
 
400
+ /**
401
+ * Hook del ciclo de vida reactivo (Lit).
402
+ * Gestiona inyecciones de variables CSS dinámicas para anchos y alturas máximas.
403
+ *
404
+ * Fundamental: Resuelve problemas de `z-index` y `overflow: hidden` en ancestros
405
+ * mediante el Portal Pattern (moviendo físicamente el DOM element al `document.body`)
406
+ * si `positioning === 'body'` cuando se abre, y devolviéndolo a su DOM originario al cerrar.
407
+ */
349
408
  override updated(changed: Map<string, unknown>) {
350
409
  super.updated(changed);
351
410
  if (changed.has('expandedHeight')) {
@@ -356,11 +415,18 @@ export class MoniBottomSheet extends MoniElement {
356
415
  }
357
416
  if (changed.has('open')) {
358
417
  if (this.open) {
418
+ if (changed.get('open') !== undefined) {
419
+ emitMoniEvent(this, 'moni-open');
420
+ }
359
421
  if (this.positioning === 'body' && this.parentNode !== document.body) {
360
422
  this._originalParent = this.parentNode;
361
423
  this._originalSibling = this.nextSibling;
362
424
  document.body.appendChild(this);
363
425
  }
426
+ if (changed.get('open') !== undefined) {
427
+ // Simulamos el final de la transición de apertura
428
+ setTimeout(() => emitMoniEvent(this, 'moni-opened'), 300);
429
+ }
364
430
  } else {
365
431
  if (this._dialog) {
366
432
  this._dialog.classList.remove('expanded');
@@ -374,6 +440,11 @@ export class MoniBottomSheet extends MoniElement {
374
440
  }
375
441
  }
376
442
 
443
+ /**
444
+ * Limpieza (Garbage Collection).
445
+ * Si el Bottom Sheet fue destruido mientras estaba inyectado en el `document.body`
446
+ * (Portal Pattern), lo retorna a su padre original para evitar orfandad de nodos.
447
+ */
377
448
  override disconnectedCallback() {
378
449
  super.disconnectedCallback();
379
450
  if (this.parentNode === document.body && this.positioning === 'body' && this._originalParent) {
@@ -504,6 +575,26 @@ export class MoniBottomSheet extends MoniElement {
504
575
  `
505
576
  ];
506
577
 
578
+ /**
579
+ * Renders the native `<dialog>` element that serves as the bottom sheet container.
580
+ *
581
+ * **Why `<dialog>` instead of `<div>`?**
582
+ * Using the native `<dialog>` element provides:
583
+ * - Built-in focus trapping via the `open` attribute (browser handles `inert`).
584
+ * - The `::backdrop` pseudo-element for the translucent overlay (styled via CSS).
585
+ * - Screen reader accessibility (`role="dialog"` / `aria-modal`) for free.
586
+ *
587
+ * **Positioning class mapping:**
588
+ * `posClass` maps `positioning='body'` to `'fixed'` (the CSS class name), while
589
+ * other positioning values pass through unchanged. `'body'` positioning anchors
590
+ * the sheet to the viewport; `'parent'` keeps it within the nearest `position: relative` ancestor.
591
+ *
592
+ * **Touch-to-dismiss via pointer events:**
593
+ * `@pointerdown`, `@pointermove`, and `@pointerup` on the `<dialog>` element
594
+ * power the swipe-down-to-dismiss gesture. `_onPointerDown` records the start Y;
595
+ * `_onPointerMove` applies a CSS `translateY` to provide live drag feedback;
596
+ * `_onPointerUp` determines if the drag exceeded the dismiss threshold.
597
+ */
507
598
  override render() {
508
599
  const posClass = this.positioning === 'body' ? 'fixed' : this.positioning;
509
600
  const dialogClasses = `${this.size} ${posClass}`;