@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.
- package/custom-elements.json +5230 -1007
- package/dist/components/_base/moni-element.d.ts +16 -9
- package/dist/components/_base/moni-element.d.ts.map +1 -1
- package/dist/components/_base/moni-element.js +63 -9
- package/dist/components/index.js +2 -2
- package/dist/components/loading-shapes.d.ts +19 -0
- package/dist/components/loading-shapes.d.ts.map +1 -1
- package/dist/components/loading-shapes.js +19 -0
- package/dist/components/moni-app-bar.d.ts +72 -62
- package/dist/components/moni-app-bar.d.ts.map +1 -1
- package/dist/components/moni-app-bar.js +72 -62
- package/dist/components/moni-badge.d.ts +64 -65
- package/dist/components/moni-badge.d.ts.map +1 -1
- package/dist/components/moni-badge.js +64 -66
- package/dist/components/moni-bottom-sheet.d.ts +129 -61
- package/dist/components/moni-bottom-sheet.d.ts.map +1 -1
- package/dist/components/moni-bottom-sheet.js +217 -131
- package/dist/components/moni-button-group.d.ts +107 -29
- package/dist/components/moni-button-group.d.ts.map +1 -1
- package/dist/components/moni-button-group.js +107 -29
- package/dist/components/moni-button-segment.d.ts +53 -12
- package/dist/components/moni-button-segment.d.ts.map +1 -1
- package/dist/components/moni-button-segment.js +53 -12
- package/dist/components/moni-button.d.ts +116 -38
- package/dist/components/moni-button.d.ts.map +1 -1
- package/dist/components/moni-button.js +128 -38
- package/dist/components/moni-card.d.ts +68 -50
- package/dist/components/moni-card.d.ts.map +1 -1
- package/dist/components/moni-card.js +68 -50
- package/dist/components/moni-carousel.d.ts +484 -53
- package/dist/components/moni-carousel.d.ts.map +1 -1
- package/dist/components/moni-carousel.js +1024 -245
- package/dist/components/moni-checkbox.d.ts +49 -46
- package/dist/components/moni-checkbox.d.ts.map +1 -1
- package/dist/components/moni-checkbox.js +55 -48
- package/dist/components/moni-chip.d.ts +100 -33
- package/dist/components/moni-chip.d.ts.map +1 -1
- package/dist/components/moni-chip.js +104 -34
- package/dist/components/moni-color-field.d.ts +99 -24
- package/dist/components/moni-color-field.d.ts.map +1 -1
- package/dist/components/moni-color-field.js +99 -24
- package/dist/components/moni-context-menu.d.ts +72 -26
- package/dist/components/moni-context-menu.d.ts.map +1 -1
- package/dist/components/moni-context-menu.js +76 -30
- package/dist/components/moni-dialog.d.ts +84 -59
- package/dist/components/moni-dialog.d.ts.map +1 -1
- package/dist/components/moni-dialog.js +105 -58
- package/dist/components/moni-divider.d.ts +39 -27
- package/dist/components/moni-divider.d.ts.map +1 -1
- package/dist/components/moni-divider.js +42 -30
- package/dist/components/moni-expansion.d.ts +32 -22
- package/dist/components/moni-expansion.d.ts.map +1 -1
- package/dist/components/moni-expansion.js +32 -22
- package/dist/components/moni-fab-menu.d.ts +61 -23
- package/dist/components/moni-fab-menu.d.ts.map +1 -1
- package/dist/components/moni-fab-menu.js +69 -31
- package/dist/components/moni-fab.d.ts +86 -28
- package/dist/components/moni-fab.d.ts.map +1 -1
- package/dist/components/moni-fab.js +92 -34
- package/dist/components/moni-file-field.d.ts +118 -30
- package/dist/components/moni-file-field.d.ts.map +1 -1
- package/dist/components/moni-file-field.js +118 -30
- package/dist/components/moni-icon.d.ts +40 -35
- package/dist/components/moni-icon.d.ts.map +1 -1
- package/dist/components/moni-icon.js +43 -38
- package/dist/components/moni-list-item.d.ts +46 -33
- package/dist/components/moni-list-item.d.ts.map +1 -1
- package/dist/components/moni-list-item.js +61 -41
- package/dist/components/moni-list.d.ts +30 -20
- package/dist/components/moni-list.d.ts.map +1 -1
- package/dist/components/moni-list.js +36 -21
- package/dist/components/moni-loading-indicator.d.ts +54 -22
- package/dist/components/moni-loading-indicator.d.ts.map +1 -1
- package/dist/components/moni-loading-indicator.js +54 -22
- package/dist/components/moni-menu-item.d.ts +23 -16
- package/dist/components/moni-menu-item.d.ts.map +1 -1
- package/dist/components/moni-menu-item.js +23 -16
- package/dist/components/moni-menu.d.ts +81 -28
- package/dist/components/moni-menu.d.ts.map +1 -1
- package/dist/components/moni-menu.js +81 -30
- package/dist/components/moni-morph-modal.d.ts +141 -0
- package/dist/components/moni-morph-modal.d.ts.map +1 -1
- package/dist/components/moni-morph-modal.js +295 -58
- package/dist/components/moni-nav-item.d.ts +59 -29
- package/dist/components/moni-nav-item.d.ts.map +1 -1
- package/dist/components/moni-nav-item.js +59 -29
- package/dist/components/moni-nav.d.ts +94 -35
- package/dist/components/moni-nav.d.ts.map +1 -1
- package/dist/components/moni-nav.js +94 -35
- package/dist/components/moni-progress.d.ts +99 -55
- package/dist/components/moni-progress.d.ts.map +1 -1
- package/dist/components/moni-progress.js +99 -55
- package/dist/components/moni-radio.d.ts +62 -50
- package/dist/components/moni-radio.d.ts.map +1 -1
- package/dist/components/moni-radio.js +65 -52
- package/dist/components/moni-ripple.d.ts +74 -59
- package/dist/components/moni-ripple.d.ts.map +1 -1
- package/dist/components/moni-ripple.js +74 -59
- package/dist/components/moni-segmented-button.d.ts +91 -16
- package/dist/components/moni-segmented-button.d.ts.map +1 -1
- package/dist/components/moni-segmented-button.js +94 -17
- package/dist/components/moni-select-option.d.ts +30 -23
- package/dist/components/moni-select-option.d.ts.map +1 -1
- package/dist/components/moni-select-option.js +30 -23
- package/dist/components/moni-select.d.ts +300 -35
- package/dist/components/moni-select.d.ts.map +1 -1
- package/dist/components/moni-select.js +323 -39
- package/dist/components/moni-side-sheet.d.ts +94 -32
- package/dist/components/moni-side-sheet.d.ts.map +1 -1
- package/dist/components/moni-side-sheet.js +94 -32
- package/dist/components/moni-slider.d.ts +152 -41
- package/dist/components/moni-slider.d.ts.map +1 -1
- package/dist/components/moni-slider.js +154 -42
- package/dist/components/moni-snackbar.d.ts +53 -43
- package/dist/components/moni-snackbar.d.ts.map +1 -1
- package/dist/components/moni-snackbar.js +53 -43
- package/dist/components/moni-split-button.d.ts +63 -18
- package/dist/components/moni-split-button.d.ts.map +1 -1
- package/dist/components/moni-split-button.js +63 -18
- package/dist/components/moni-step.d.ts +36 -24
- package/dist/components/moni-step.d.ts.map +1 -1
- package/dist/components/moni-step.js +41 -29
- package/dist/components/moni-stepper.d.ts +64 -27
- package/dist/components/moni-stepper.d.ts.map +1 -1
- package/dist/components/moni-stepper.js +72 -34
- package/dist/components/moni-switch.d.ts +57 -46
- package/dist/components/moni-switch.d.ts.map +1 -1
- package/dist/components/moni-switch.js +59 -47
- package/dist/components/moni-tab.d.ts +26 -18
- package/dist/components/moni-tab.d.ts.map +1 -1
- package/dist/components/moni-tab.js +29 -21
- package/dist/components/moni-tabs.d.ts +34 -28
- package/dist/components/moni-tabs.d.ts.map +1 -1
- package/dist/components/moni-tabs.js +34 -28
- package/dist/components/moni-text-field.d.ts +139 -29
- package/dist/components/moni-text-field.d.ts.map +1 -1
- package/dist/components/moni-text-field.js +157 -31
- package/dist/components/moni-textarea.d.ts +127 -29
- package/dist/components/moni-textarea.d.ts.map +1 -1
- package/dist/components/moni-textarea.js +131 -32
- package/dist/components/moni-time-picker.d.ts +114 -24
- package/dist/components/moni-time-picker.d.ts.map +1 -1
- package/dist/components/moni-time-picker.js +127 -33
- package/dist/components/moni-toolbar.d.ts +37 -23
- package/dist/components/moni-toolbar.d.ts.map +1 -1
- package/dist/components/moni-toolbar.js +37 -23
- package/dist/components/moni-tooltip.d.ts +100 -36
- package/dist/components/moni-tooltip.d.ts.map +1 -1
- package/dist/components/moni-tooltip.js +104 -40
- package/dist/components/moni-typography.d.ts +68 -30
- package/dist/components/moni-typography.d.ts.map +1 -1
- package/dist/components/moni-typography.js +70 -32
- package/dist/styles/tokens.css +7 -7
- package/dist/types/events.d.ts +17 -0
- package/dist/types/events.d.ts.map +1 -0
- package/dist/types/events.js +1 -0
- package/dist/utils/event-emitter.d.ts +13 -0
- package/dist/utils/event-emitter.d.ts.map +1 -0
- package/dist/utils/event-emitter.js +13 -0
- package/package.json +2 -1
- package/src/components/_base/moni-element.ts +73 -9
- package/src/components/index.ts +2 -2
- package/src/components/loading-shapes.ts +19 -0
- package/src/components/moni-app-bar.test.ts +10 -10
- package/src/components/moni-app-bar.ts +72 -62
- package/src/components/moni-badge.ts +64 -66
- package/src/components/moni-bottom-sheet.test.ts +39 -45
- package/src/components/moni-bottom-sheet.ts +222 -131
- package/src/components/moni-button-group.test.ts +14 -14
- package/src/components/moni-button-group.ts +107 -29
- package/src/components/moni-button-segment.ts +53 -12
- package/src/components/moni-button.test.ts +28 -26
- package/src/components/moni-button.ts +139 -39
- package/src/components/moni-card.test.ts +6 -6
- package/src/components/moni-card.ts +70 -50
- package/src/components/moni-carousel.test.ts +12 -12
- package/src/components/moni-carousel.ts +1129 -269
- package/src/components/moni-checkbox.test.ts +7 -7
- package/src/components/moni-checkbox.ts +62 -48
- package/src/components/moni-chip.test.ts +17 -17
- package/src/components/moni-chip.ts +112 -34
- package/src/components/moni-color-field.test.ts +5 -5
- package/src/components/moni-color-field.ts +108 -24
- package/src/components/moni-context-menu.test.ts +11 -11
- package/src/components/moni-context-menu.ts +76 -30
- package/src/components/moni-dialog.ts +108 -59
- package/src/components/moni-divider.test.ts +4 -4
- package/src/components/moni-divider.ts +42 -30
- package/src/components/moni-expansion.ts +32 -22
- package/src/components/moni-fab-menu.test.ts +11 -11
- package/src/components/moni-fab-menu.ts +69 -31
- package/src/components/moni-fab.test.ts +16 -16
- package/src/components/moni-fab.ts +100 -34
- package/src/components/moni-file-field.test.ts +8 -8
- package/src/components/moni-file-field.ts +132 -30
- package/src/components/moni-icon.test.ts +11 -11
- package/src/components/moni-icon.ts +43 -38
- package/src/components/moni-list-item.test.ts +10 -10
- package/src/components/moni-list-item.ts +61 -41
- package/src/components/moni-list.ts +37 -21
- package/src/components/moni-loading-indicator.test.ts +3 -3
- package/src/components/moni-loading-indicator.ts +54 -22
- package/src/components/moni-menu-item.ts +23 -16
- package/src/components/moni-menu.test.ts +7 -7
- package/src/components/moni-menu.ts +87 -30
- package/src/components/moni-morph-modal.test.ts +18 -17
- package/src/components/moni-morph-modal.ts +327 -60
- package/src/components/moni-nav-item.ts +59 -29
- package/src/components/moni-nav.test.ts +11 -11
- package/src/components/moni-nav.ts +94 -35
- package/src/components/moni-progress.test.ts +9 -9
- package/src/components/moni-progress.ts +100 -56
- package/src/components/moni-radio.test.ts +8 -8
- package/src/components/moni-radio.ts +71 -51
- package/src/components/moni-ripple.ts +74 -59
- package/src/components/moni-segmented-button.test.ts +4 -4
- package/src/components/moni-segmented-button.ts +94 -17
- package/src/components/moni-select-option.ts +30 -23
- package/src/components/moni-select.test.ts +11 -11
- package/src/components/moni-select.ts +361 -50
- package/src/components/moni-side-sheet.test.ts +7 -7
- package/src/components/moni-side-sheet.ts +94 -32
- package/src/components/moni-slider.test.ts +7 -7
- package/src/components/moni-slider.ts +165 -42
- package/src/components/moni-snackbar.test.ts +8 -8
- package/src/components/moni-snackbar.ts +53 -43
- package/src/components/moni-split-button.ts +63 -18
- package/src/components/moni-step.test.ts +7 -7
- package/src/components/moni-step.ts +41 -29
- package/src/components/moni-stepper.test.ts +7 -7
- package/src/components/moni-stepper.ts +72 -34
- package/src/components/moni-switch.test.ts +12 -12
- package/src/components/moni-switch.ts +66 -47
- package/src/components/moni-tab.test.ts +5 -5
- package/src/components/moni-tab.ts +29 -21
- package/src/components/moni-tabs.ts +34 -28
- package/src/components/moni-text-field.test.ts +13 -13
- package/src/components/moni-text-field.ts +181 -30
- package/src/components/moni-textarea.test.ts +17 -17
- package/src/components/moni-textarea.ts +155 -31
- package/src/components/moni-time-picker.test.ts +5 -5
- package/src/components/moni-time-picker.ts +128 -33
- package/src/components/moni-toolbar.test.ts +8 -8
- package/src/components/moni-toolbar.ts +37 -23
- package/src/components/moni-tooltip.test.ts +15 -15
- package/src/components/moni-tooltip.ts +107 -40
- package/src/components/moni-typography.test.ts +10 -10
- package/src/components/moni-typography.ts +73 -32
- package/src/styles/tokens.css +7 -7
- package/src/types/events.ts +17 -0
- 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
|
|
14
|
+
* Componente Material Design 3 Bottom Sheet.
|
|
14
15
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
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
|
-
* **
|
|
20
|
+
* **Referencia de la especificación M3:** `m3-docs/components/sheets-bottom/specs.md`
|
|
20
21
|
*
|
|
21
|
-
* **
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* `modal=true` (
|
|
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
|
-
* **
|
|
27
|
-
*
|
|
28
|
-
* `document.body`
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
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
|
-
* **
|
|
34
|
-
* - `small` —
|
|
35
|
-
* - `medium` —
|
|
36
|
-
* - `large` —
|
|
37
|
-
* - `auto` —
|
|
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="
|
|
42
|
-
* <moni-list-item icon="share">
|
|
43
|
-
* <moni-list-item icon="mail">
|
|
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 -
|
|
52
|
-
* @slot handle -
|
|
53
|
-
* @slot footer -
|
|
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 -
|
|
56
|
-
* @csspart header -
|
|
57
|
-
* @csspart body -
|
|
58
|
-
* @csspart footer -
|
|
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
|
-
*
|
|
64
|
+
* Controla el estado abierto/cerrado del bottom sheet.
|
|
64
65
|
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
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
|
-
*
|
|
74
|
+
* Variante de altura del contenedor de la hoja.
|
|
74
75
|
*
|
|
75
|
-
* - `'small'` —
|
|
76
|
-
* - `'medium'` —
|
|
77
|
-
* - `'large'` —
|
|
78
|
-
* - `'auto'` —
|
|
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
|
-
*
|
|
87
|
-
* 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
|
-
*
|
|
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
|
-
*
|
|
102
|
+
* Controla cómo se posiciona la hoja en el documento.
|
|
102
103
|
*
|
|
103
|
-
* - `'body'` (
|
|
104
|
-
*
|
|
105
|
-
* - `'fixed'` —
|
|
106
|
-
* - `'absolute'` —
|
|
107
|
-
* - `'static'` —
|
|
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
|
-
*
|
|
116
|
+
* Block-size (altura) máximo de la hoja cuando `size="large"`.
|
|
116
117
|
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
*
|
|
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
|
-
*
|
|
128
|
+
* Restricción opcional de inline-size (ancho) máximo para la hoja.
|
|
128
129
|
*
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
* modal
|
|
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 '' (
|
|
134
|
+
* @default '' (sin restricción)
|
|
134
135
|
*/
|
|
135
136
|
@property({ reflect: true, attribute: 'max-width' })
|
|
136
137
|
maxWidth = '';
|
|
137
138
|
|
|
138
139
|
/**
|
|
139
|
-
*
|
|
140
|
-
*
|
|
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
|
-
*
|
|
146
|
-
*
|
|
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
|
-
/**
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
247
|
-
this.
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
342
|
+
// Evaluamos el arrastre hacia arriba desde el estado colapsado
|
|
275
343
|
const finalHeight = this._sheetHeight - deltaY;
|
|
276
|
-
|
|
277
|
-
|
|
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
|
-
//
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
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.
|
|
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}`;
|