@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.
- package/custom-elements.json +5181 -1043
- 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 +471 -53
- package/dist/components/moni-carousel.d.ts.map +1 -1
- package/dist/components/moni-carousel.js +862 -264
- 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 +953 -290
- 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
|
@@ -12,49 +12,49 @@ import { MoniElement, sharedStyles } from './_base/index.js';
|
|
|
12
12
|
import './moni-icon.js';
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
* Material Design 3 Navigation Item
|
|
15
|
+
* Componente Material Design 3 Navigation Item (Elemento de Navegación).
|
|
16
16
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
17
|
+
* Un elemento de destino individual dentro de un contenedor `<moni-nav>`. Se renderiza como un
|
|
18
|
+
* elemento `<a>` accesible con un icono, etiqueta y capa de estado M3.
|
|
19
19
|
*
|
|
20
|
-
* **
|
|
21
|
-
* -
|
|
22
|
-
* -
|
|
23
|
-
* -
|
|
20
|
+
* **Referencias a la especificación M3:**
|
|
21
|
+
* - Elemento de barra de navegación: `m3-docs/components/navigation-bar/specs.md`
|
|
22
|
+
* - Elemento de riel de navegación: `m3-docs/components/navigation-rail/specs.md`
|
|
23
|
+
* - Elemento de cajón de navegación: `m3-docs/components/navigation-drawer/specs.md`
|
|
24
24
|
*
|
|
25
|
-
* **
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
* render
|
|
29
|
-
* -
|
|
30
|
-
* -
|
|
31
|
-
* -
|
|
25
|
+
* **Adaptación de diseño:**
|
|
26
|
+
* Las propiedades `placement`, `variant` y `layout` son retransmitidas desde
|
|
27
|
+
* el padre `<moni-nav>` (típicamente a través de vinculación de atributos en el
|
|
28
|
+
* método render del padre). El elemento de navegación las usa para renderizar condicionalmente:
|
|
29
|
+
* - Icono + etiqueta abajo (barra de navegación).
|
|
30
|
+
* - Solo icono + etiqueta horizontal (riel).
|
|
31
|
+
* - Icono + etiqueta completa (cajón).
|
|
32
32
|
*
|
|
33
|
-
* **
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
33
|
+
* **Comportamiento responsivo:**
|
|
34
|
+
* Usa `window.matchMedia('(min-width: 601px)')` para detectar pantallas medianas
|
|
35
|
+
* y almacena el resultado en `_isMediumScreen`. Esto impulsa el cambio de diseño
|
|
36
|
+
* automático entre estilos de barra y riel.
|
|
37
37
|
*
|
|
38
|
-
* **
|
|
39
|
-
*
|
|
40
|
-
*
|
|
38
|
+
* **Estado activo:**
|
|
39
|
+
* El atributo `active` aplica el indicador activo M3: un fondo `secondary-container`
|
|
40
|
+
* en forma de píldora detrás del icono y un color de etiqueta más oscuro.
|
|
41
41
|
*
|
|
42
42
|
* @example
|
|
43
43
|
* ```html
|
|
44
44
|
* <moni-nav placement="bottom">
|
|
45
|
-
* <moni-nav-item href="/" icon="home" label="
|
|
46
|
-
* <moni-nav-item href="/search" icon="search" label="
|
|
47
|
-
* <moni-nav-item href="/profile" icon="person" label="
|
|
48
|
-
* <moni-badge value="3"></moni-badge> <!--
|
|
45
|
+
* <moni-nav-item href="/" icon="home" label="Inicio" active></moni-nav-item>
|
|
46
|
+
* <moni-nav-item href="/search" icon="search" label="Buscar"></moni-nav-item>
|
|
47
|
+
* <moni-nav-item href="/profile" icon="person" label="Perfil">
|
|
48
|
+
* <moni-badge value="3"></moni-badge> <!-- insignia de notificación -->
|
|
49
49
|
* </moni-nav-item>
|
|
50
50
|
* </moni-nav>
|
|
51
51
|
* ```
|
|
52
52
|
*
|
|
53
|
-
* @slot default -
|
|
53
|
+
* @slot default - Contenido adicional colocado después del icono (ej. `<moni-badge>`).
|
|
54
54
|
*
|
|
55
|
-
* @csspart item -
|
|
56
|
-
* @csspart icon -
|
|
57
|
-
* @csspart label -
|
|
55
|
+
* @csspart item - El elemento exterior `<a>`.
|
|
56
|
+
* @csspart icon - El contenedor del icono.
|
|
57
|
+
* @csspart label - El elemento de texto de la etiqueta.
|
|
58
58
|
*/
|
|
59
59
|
@customElement('moni-nav-item')
|
|
60
60
|
export class MoniNavItem extends MoniElement {
|
|
@@ -74,6 +74,12 @@ export class MoniNavItem extends MoniElement {
|
|
|
74
74
|
? window.matchMedia('(min-width: 601px)')
|
|
75
75
|
: null;
|
|
76
76
|
|
|
77
|
+
/**
|
|
78
|
+
* Hook de inicialización (Lit).
|
|
79
|
+
* Vincula un listener de `MediaQueryList` nativo para poder reaccionar en tiempo real
|
|
80
|
+
* cuando la pantalla cruza el breakpoint de 600px, adaptando la disposición
|
|
81
|
+
* (horizontal vs vertical) del ícono y la etiqueta automáticamente.
|
|
82
|
+
*/
|
|
77
83
|
override connectedCallback() {
|
|
78
84
|
super.connectedCallback();
|
|
79
85
|
if (this._query) {
|
|
@@ -82,6 +88,11 @@ export class MoniNavItem extends MoniElement {
|
|
|
82
88
|
}
|
|
83
89
|
}
|
|
84
90
|
|
|
91
|
+
/**
|
|
92
|
+
* Hook de destrucción (Lit).
|
|
93
|
+
* Desvincula rigurosamente el listener del `matchMedia` para
|
|
94
|
+
* prevenir fugas de memoria (memory leaks).
|
|
95
|
+
*/
|
|
85
96
|
override disconnectedCallback() {
|
|
86
97
|
super.disconnectedCallback();
|
|
87
98
|
if (this._query) {
|
|
@@ -89,6 +100,11 @@ export class MoniNavItem extends MoniElement {
|
|
|
89
100
|
}
|
|
90
101
|
}
|
|
91
102
|
|
|
103
|
+
/**
|
|
104
|
+
* Callback asíncrono disparado nativamente por el navegador cuando
|
|
105
|
+
* cambian las condiciones del Media Query.
|
|
106
|
+
* Actualiza el estado reactivo `_isMediumScreen` lo que fuerza a Lit a re-renderizar.
|
|
107
|
+
*/
|
|
92
108
|
private _handleQueryChange = (e: MediaQueryListEvent) => {
|
|
93
109
|
this._isMediumScreen = e.matches;
|
|
94
110
|
};
|
|
@@ -236,6 +252,20 @@ export class MoniNavItem extends MoniElement {
|
|
|
236
252
|
`
|
|
237
253
|
];
|
|
238
254
|
|
|
255
|
+
/**
|
|
256
|
+
* Renderiza el elemento de navegación como un `<a>` o `<button>` con ranura de icono, etiqueta y badge (insignia).
|
|
257
|
+
*
|
|
258
|
+
* **Indicador activo:**
|
|
259
|
+
* La barra de navegación M3 usa un indicador en forma de píldora detrás del icono del
|
|
260
|
+
* elemento activo. Esto se implementa como el pseudo-elemento `::before` en
|
|
261
|
+
* `.item` que crece de `0` a `64px` de ancho usando una transición CSS.
|
|
262
|
+
* La clase `active` en `.item` activa la transición y también establece
|
|
263
|
+
* `aria-current="page"` para lectores de pantalla.
|
|
264
|
+
*
|
|
265
|
+
* **Ranura para badge (insignia):**
|
|
266
|
+
* `[slot="badge"]` se renderiza posicionado absolutamente sobre la esquina superior final del icono.
|
|
267
|
+
* Los consumidores colocan un `<moni-badge>` aquí para cuentas de notificaciones.
|
|
268
|
+
*/
|
|
239
269
|
override render() {
|
|
240
270
|
const isHorizontal = this.computedLayout === 'horizontal';
|
|
241
271
|
|
|
@@ -16,7 +16,7 @@ describe('moni-nav / moni-nav-item', () => {
|
|
|
16
16
|
el.remove();
|
|
17
17
|
});
|
|
18
18
|
|
|
19
|
-
it('
|
|
19
|
+
it('renderiza un <nav> con un slot', async () => {
|
|
20
20
|
await el.updateComplete;
|
|
21
21
|
const nav = el.shadowRoot?.querySelector('nav');
|
|
22
22
|
const slot = el.shadowRoot?.querySelector('slot');
|
|
@@ -24,14 +24,14 @@ describe('moni-nav / moni-nav-item', () => {
|
|
|
24
24
|
expect(slot).toBeTruthy();
|
|
25
25
|
});
|
|
26
26
|
|
|
27
|
-
it('
|
|
27
|
+
it('aplica la clase de placement al nav', async () => {
|
|
28
28
|
el.placement = 'bottom';
|
|
29
29
|
await el.updateComplete;
|
|
30
30
|
const nav = el.shadowRoot?.querySelector('nav');
|
|
31
31
|
expect(nav?.classList.contains('bottom')).toBe(true);
|
|
32
32
|
});
|
|
33
33
|
|
|
34
|
-
it('
|
|
34
|
+
it('aplica la clase de variante (rail/drawer)', async () => {
|
|
35
35
|
el.placement = 'left';
|
|
36
36
|
el.variant = 'drawer';
|
|
37
37
|
await el.updateComplete;
|
|
@@ -40,19 +40,19 @@ describe('moni-nav / moni-nav-item', () => {
|
|
|
40
40
|
expect(nav?.classList.contains('max')).toBe(true);
|
|
41
41
|
});
|
|
42
42
|
|
|
43
|
-
it('
|
|
43
|
+
it('refleja el atributo placement', async () => {
|
|
44
44
|
el.placement = 'right';
|
|
45
45
|
await el.updateComplete;
|
|
46
46
|
expect(el.getAttribute('placement')).toBe('right');
|
|
47
47
|
});
|
|
48
48
|
|
|
49
|
-
it('
|
|
49
|
+
it('refleja el atributo variant', async () => {
|
|
50
50
|
el.variant = 'rail';
|
|
51
51
|
await el.updateComplete;
|
|
52
52
|
expect(el.getAttribute('variant')).toBe('rail');
|
|
53
53
|
});
|
|
54
54
|
|
|
55
|
-
it('
|
|
55
|
+
it('reenvía icon, label y active al nav-item', async () => {
|
|
56
56
|
const item = document.createElement('moni-nav-item') as MoniNavItem;
|
|
57
57
|
item.icon = 'home';
|
|
58
58
|
item.label = 'Home';
|
|
@@ -68,7 +68,7 @@ describe('moni-nav / moni-nav-item', () => {
|
|
|
68
68
|
expect(a?.querySelector('moni-icon')).toBeTruthy();
|
|
69
69
|
});
|
|
70
70
|
|
|
71
|
-
it('
|
|
71
|
+
it('reenvía href y target al <a> interno', async () => {
|
|
72
72
|
const item = document.createElement('moni-nav-item') as MoniNavItem;
|
|
73
73
|
item.href = '/home';
|
|
74
74
|
item.target = '_blank';
|
|
@@ -79,7 +79,7 @@ describe('moni-nav / moni-nav-item', () => {
|
|
|
79
79
|
expect(a?.getAttribute('target')).toBe('_blank');
|
|
80
80
|
});
|
|
81
81
|
|
|
82
|
-
it('
|
|
82
|
+
it('propaga la propiedad layout a los ítems y establece el layout computado', async () => {
|
|
83
83
|
const item = document.createElement('moni-nav-item') as MoniNavItem;
|
|
84
84
|
el.appendChild(item);
|
|
85
85
|
el.layout = 'horizontal';
|
|
@@ -93,7 +93,7 @@ describe('moni-nav / moni-nav-item', () => {
|
|
|
93
93
|
expect(a?.getAttribute('data-layout')).toBe('horizontal');
|
|
94
94
|
});
|
|
95
95
|
|
|
96
|
-
it('modal drawer
|
|
96
|
+
it('el modal drawer renderiza un scrim y semántica de dialog', async () => {
|
|
97
97
|
el.placement = 'left';
|
|
98
98
|
el.variant = 'drawer';
|
|
99
99
|
el.modal = true;
|
|
@@ -108,7 +108,7 @@ describe('moni-nav / moni-nav-item', () => {
|
|
|
108
108
|
expect(nav?.getAttribute('aria-expanded')).toBe('true');
|
|
109
109
|
});
|
|
110
110
|
|
|
111
|
-
it('modal drawer
|
|
111
|
+
it('el modal drawer se cierra cuando se hace clic en el scrim', async () => {
|
|
112
112
|
el.placement = 'left';
|
|
113
113
|
el.variant = 'drawer';
|
|
114
114
|
el.modal = true;
|
|
@@ -124,7 +124,7 @@ describe('moni-nav / moni-nav-item', () => {
|
|
|
124
124
|
expect(nav?.getAttribute('aria-expanded')).toBe('false');
|
|
125
125
|
});
|
|
126
126
|
|
|
127
|
-
it('modal drawer
|
|
127
|
+
it('el modal drawer se cierra con la tecla Escape', async () => {
|
|
128
128
|
el.placement = 'left';
|
|
129
129
|
el.variant = 'drawer';
|
|
130
130
|
el.modal = true;
|
|
@@ -10,56 +10,56 @@ import { customElement, property } from 'lit/decorators.js';
|
|
|
10
10
|
import { MoniElement, sharedStyles } from './_base/index.js';
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
-
* Material Design 3
|
|
13
|
+
* Componente contenedor de Navegación Material Design 3.
|
|
14
14
|
*
|
|
15
|
-
* `<moni-nav>`
|
|
16
|
-
*
|
|
17
|
-
*
|
|
15
|
+
* `<moni-nav>` es el contenedor que envuelve los elementos `<moni-nav-item>` y
|
|
16
|
+
* controla el patrón de navegación M3: barra de navegación, riel de navegación o
|
|
17
|
+
* cajón de navegación.
|
|
18
18
|
*
|
|
19
|
-
* **
|
|
20
|
-
* -
|
|
21
|
-
* -
|
|
22
|
-
* -
|
|
19
|
+
* **Referencias a la especificación M3:**
|
|
20
|
+
* - Barra de navegación: `m3-docs/components/navigation-bar/specs.md`
|
|
21
|
+
* - Riel de navegación: `m3-docs/components/navigation-rail/specs.md`
|
|
22
|
+
* - Cajón de navegación: `m3-docs/components/navigation-drawer/specs.md`
|
|
23
23
|
*
|
|
24
|
-
* **
|
|
25
|
-
* - **
|
|
26
|
-
*
|
|
27
|
-
* - **
|
|
28
|
-
*
|
|
29
|
-
* - **
|
|
30
|
-
*
|
|
31
|
-
* - **
|
|
32
|
-
*
|
|
33
|
-
*
|
|
24
|
+
* **Patrones de navegación:**
|
|
25
|
+
* - **Barra de navegación** (`placement="bottom"`) — Barra horizontal de elementos de icono+etiqueta
|
|
26
|
+
* en la parte inferior de la pantalla. Ideal para 3–5 destinos de nivel superior.
|
|
27
|
+
* - **Riel de navegación** (`variant="rail"`) — Riel vertical de elementos de icono+etiqueta
|
|
28
|
+
* en el lateral de la pantalla. Ideal para puntos de interrupción medianos/expandidos.
|
|
29
|
+
* - **Cajón estándar** (`variant="drawer"`) — Panel vertical siempre visible
|
|
30
|
+
* con etiquetas de texto completo. Sin atenuación (scrim). Ideal para pantallas grandes.
|
|
31
|
+
* - **Cajón modal** (`variant="drawer" modal`) — Cajón superpuesto con atenuación (scrim).
|
|
32
|
+
* Se abre/cierra a través de la propiedad `open`. Atrapa el foco del teclado mientras está abierto.
|
|
33
|
+
* Se cierra al presionar la tecla `Escape`.
|
|
34
34
|
*
|
|
35
|
-
* **
|
|
36
|
-
*
|
|
37
|
-
* `connectedCallback`
|
|
38
|
-
*
|
|
35
|
+
* **Manejo del teclado:**
|
|
36
|
+
* Cuando `modal=true`, el componente añade un listener global de `keydown` en
|
|
37
|
+
* `connectedCallback` que cierra el cajón con `Escape`. El listener se
|
|
38
|
+
* elimina en `disconnectedCallback`.
|
|
39
39
|
*
|
|
40
40
|
* @example
|
|
41
41
|
* ```html
|
|
42
|
-
* <!--
|
|
42
|
+
* <!-- Barra de navegación inferior -->
|
|
43
43
|
* <moni-nav placement="bottom">
|
|
44
|
-
* <moni-nav-item icon="home" label="
|
|
45
|
-
* <moni-nav-item icon="search" label="
|
|
46
|
-
* <moni-nav-item icon="person" label="
|
|
44
|
+
* <moni-nav-item icon="home" label="Inicio" active></moni-nav-item>
|
|
45
|
+
* <moni-nav-item icon="search" label="Buscar"></moni-nav-item>
|
|
46
|
+
* <moni-nav-item icon="person" label="Perfil"></moni-nav-item>
|
|
47
47
|
* </moni-nav>
|
|
48
48
|
*
|
|
49
|
-
* <!--
|
|
49
|
+
* <!-- Cajón de navegación modal -->
|
|
50
50
|
* <moni-nav variant="drawer" modal open placement="left">
|
|
51
|
-
* <h3 slot="header">
|
|
52
|
-
* <moni-nav-item icon="home" label="
|
|
53
|
-
* <moni-nav-item icon="settings" label="
|
|
51
|
+
* <h3 slot="header">Mi App</h3>
|
|
52
|
+
* <moni-nav-item icon="home" label="Inicio" active></moni-nav-item>
|
|
53
|
+
* <moni-nav-item icon="settings" label="Ajustes"></moni-nav-item>
|
|
54
54
|
* </moni-nav>
|
|
55
55
|
* ```
|
|
56
56
|
*
|
|
57
|
-
* @slot default - `<moni-nav-item
|
|
58
|
-
* @slot header -
|
|
59
|
-
* @slot footer -
|
|
57
|
+
* @slot default - Hijos `<moni-nav-item>`.
|
|
58
|
+
* @slot header - Contenido encima de los elementos de navegación (solo variante drawer).
|
|
59
|
+
* @slot footer - Contenido debajo de los elementos de navegación (solo variante drawer).
|
|
60
60
|
*
|
|
61
|
-
* @csspart nav -
|
|
62
|
-
* @csspart scrim -
|
|
61
|
+
* @csspart nav - El elemento `<nav>` interior.
|
|
62
|
+
* @csspart scrim - El atenuador de fondo (scrim) (solo cajón modal).
|
|
63
63
|
*/
|
|
64
64
|
@customElement('moni-nav')
|
|
65
65
|
export class MoniNav extends MoniElement {
|
|
@@ -72,29 +72,59 @@ export class MoniNav extends MoniElement {
|
|
|
72
72
|
@property({ reflect: true })
|
|
73
73
|
layout: 'vertical' | 'horizontal' | 'auto' = 'auto';
|
|
74
74
|
|
|
75
|
+
/**
|
|
76
|
+
* Hook de inicialización (Lit).
|
|
77
|
+
* Vincula el listener global para teclado, asegurando que `_onKeydown` mantenga
|
|
78
|
+
* el contexto correcto de `this` al ser disparado por el documento.
|
|
79
|
+
*/
|
|
75
80
|
override connectedCallback() {
|
|
76
81
|
super.connectedCallback();
|
|
77
82
|
this._onKeydown = this._onKeydown.bind(this);
|
|
78
83
|
document.addEventListener('keydown', this._onKeydown);
|
|
79
84
|
}
|
|
80
85
|
|
|
86
|
+
/**
|
|
87
|
+
* Hook de destrucción (Lit).
|
|
88
|
+
* Remueve el listener de teclado global para evitar fugas de memoria (memory leaks)
|
|
89
|
+
* cuando el componente de navegación es retirado del DOM.
|
|
90
|
+
*/
|
|
81
91
|
override disconnectedCallback() {
|
|
82
92
|
super.disconnectedCallback();
|
|
83
93
|
document.removeEventListener('keydown', this._onKeydown);
|
|
84
94
|
}
|
|
85
95
|
|
|
96
|
+
/**
|
|
97
|
+
* Manejador global de eventos de teclado.
|
|
98
|
+
* Implementa el patrón de accesibilidad estándar: Si el drawer es modal y está abierto,
|
|
99
|
+
* presionar la tecla Escape forzará su cierre inmediato.
|
|
100
|
+
*/
|
|
86
101
|
private _onKeydown(e: KeyboardEvent) {
|
|
87
102
|
if (e.key === 'Escape' && this.modal && this.open) {
|
|
88
103
|
this.open = false;
|
|
89
104
|
}
|
|
90
105
|
}
|
|
91
106
|
|
|
107
|
+
/**
|
|
108
|
+
* Función de cierre rápido invocada típicamente al hacer clic en el backdrop/scrim.
|
|
109
|
+
* Modifica directamente la propiedad `open` a false si la navegación opera en modo modal.
|
|
110
|
+
*/
|
|
92
111
|
private _closeModal() {
|
|
93
112
|
if (this.modal) {
|
|
94
113
|
this.open = false;
|
|
95
114
|
}
|
|
96
115
|
}
|
|
97
116
|
|
|
117
|
+
/**
|
|
118
|
+
* Propaga los cambios estructurales a todos los hijos `<moni-nav-item>` insertados en la ranura.
|
|
119
|
+
*
|
|
120
|
+
* Cuando `placement`, `variant`, `layout`, `modal` o `open` cambian en el
|
|
121
|
+
* `<moni-nav>` padre, los elementos hijos `<moni-nav-item>` también deben actualizar su estado
|
|
122
|
+
* de diseño calculado (layout) y de apertura. Esto se hace imperativamente a través de `_propagateToItems()` en lugar
|
|
123
|
+
* de a través de la API de Contexto de Lit para evitar la sobrecarga del Proveedor de Contexto para una simple
|
|
124
|
+
* relación padre→hijo.
|
|
125
|
+
*
|
|
126
|
+
* @param changed - Mapa de los nombres de las propiedades reactivas que desencadenaron este ciclo de actualización.
|
|
127
|
+
*/
|
|
98
128
|
override updated(changed: Map<string, unknown>) {
|
|
99
129
|
if (
|
|
100
130
|
changed.has('placement') ||
|
|
@@ -107,6 +137,12 @@ export class MoniNav extends MoniElement {
|
|
|
107
137
|
}
|
|
108
138
|
}
|
|
109
139
|
|
|
140
|
+
/**
|
|
141
|
+
* Patrón de inyección de propiedades "Top-Down" sin usar Context API.
|
|
142
|
+
* Pasa las variables arquitectónicas (`placement`, `variant`, `layout`) a los `moni-nav-item`
|
|
143
|
+
* hijos para que ellos puedan adaptar su CSS (ej: ocultar la etiqueta en la variante 'rail').
|
|
144
|
+
* Se lanza al inicializar o cada vez que cambia una prop en el contenedor.
|
|
145
|
+
*/
|
|
110
146
|
private _propagateToItems = () => {
|
|
111
147
|
const items = this.querySelectorAll('moni-nav-item');
|
|
112
148
|
items.forEach(item => {
|
|
@@ -266,6 +302,29 @@ export class MoniNav extends MoniElement {
|
|
|
266
302
|
`,
|
|
267
303
|
];
|
|
268
304
|
|
|
305
|
+
/**
|
|
306
|
+
* Renderiza el contenedor de navegación con su superposición opcional de atenuación (scrim).
|
|
307
|
+
*
|
|
308
|
+
* **Composición de clases:**
|
|
309
|
+
* - `this.placement` (`'left'`, `'right'`, `'bottom'`) — posiciona el cajón
|
|
310
|
+
* o la barra de navegación inferior contra el borde correcto de la ventana gráfica.
|
|
311
|
+
* - `'max'` — agregado cuando `variant='drawer'`; expande la navegación a toda altura
|
|
312
|
+
* y ancho según la especificación M3 Navigation Drawer.
|
|
313
|
+
*
|
|
314
|
+
* **Atenuación de cajón modal (Modal drawer scrim):**
|
|
315
|
+
* `isModalDrawer` es `true` cuando `variant='drawer'` Y `modal=true`. En este
|
|
316
|
+
* caso, se renderiza un div `.scrim` detrás del cajón como una superposición
|
|
317
|
+
* de hacer-clic-para-descartar. La atenuación tiene `aria-hidden="true"` ya que es puramente visual.
|
|
318
|
+
*
|
|
319
|
+
* **Atributo `[open]`:**
|
|
320
|
+
* La vinculación `?open=${this.open}` agrega/elimina el atributo `open` en el
|
|
321
|
+
* elemento `<nav>`. Los selectores de atributo CSS `[open]` impulsan la transición
|
|
322
|
+
* de deslizamiento hacia adentro/afuera, manteniendo la animación completamente en CSS (no se requiere GSAP para este componente).
|
|
323
|
+
*
|
|
324
|
+
* **Punto de referencia ARIA (ARIA landmark):**
|
|
325
|
+
* El elemento `<nav>` se usa directamente (no un `<div role="navigation">`) para
|
|
326
|
+
* proporcionar un punto de referencia ARIA implícito al que pueden saltar los lectores de pantalla.
|
|
327
|
+
*/
|
|
269
328
|
override render() {
|
|
270
329
|
const isModalDrawer = this.variant === 'drawer' && this.modal;
|
|
271
330
|
const classes = [this.placement, this.variant === 'drawer' ? 'max' : '']
|
|
@@ -14,26 +14,26 @@ describe('moni-progress', () => {
|
|
|
14
14
|
el.remove();
|
|
15
15
|
});
|
|
16
16
|
|
|
17
|
-
it('
|
|
17
|
+
it('renderiza un contenedor de barra de progreso', async () => {
|
|
18
18
|
await el.updateComplete;
|
|
19
19
|
const progress = el.shadowRoot?.querySelector('[role="progressbar"]');
|
|
20
20
|
expect(progress).toBeTruthy();
|
|
21
21
|
});
|
|
22
22
|
|
|
23
|
-
it('
|
|
23
|
+
it('aplica la clase indeterminate al contenedor de la barra de progreso', async () => {
|
|
24
24
|
el.indeterminate = true;
|
|
25
25
|
await el.updateComplete;
|
|
26
26
|
const progress = el.shadowRoot?.querySelector('[role="progressbar"]');
|
|
27
27
|
expect(progress?.classList.contains('indeterminate')).toBe(true);
|
|
28
28
|
});
|
|
29
29
|
|
|
30
|
-
it('
|
|
30
|
+
it('no aplica la clase indeterminate por defecto', async () => {
|
|
31
31
|
await el.updateComplete;
|
|
32
32
|
const progress = el.shadowRoot?.querySelector('[role="progressbar"]');
|
|
33
33
|
expect(progress?.classList.contains('indeterminate')).toBe(false);
|
|
34
34
|
});
|
|
35
35
|
|
|
36
|
-
it('
|
|
36
|
+
it('reenvía value y max a través de los atributos aria en el progressbar', async () => {
|
|
37
37
|
el.value = 42;
|
|
38
38
|
el.max = 100;
|
|
39
39
|
await el.updateComplete;
|
|
@@ -44,7 +44,7 @@ describe('moni-progress', () => {
|
|
|
44
44
|
expect(progress.getAttribute('aria-valuemax')).toBe('100');
|
|
45
45
|
});
|
|
46
46
|
|
|
47
|
-
it('
|
|
47
|
+
it('limita el porcentaje renderizado entre 0 y 100', async () => {
|
|
48
48
|
el.value = 150;
|
|
49
49
|
el.max = 100;
|
|
50
50
|
await el.updateComplete;
|
|
@@ -61,28 +61,28 @@ describe('moni-progress', () => {
|
|
|
61
61
|
expect(style2).toContain('--_p: 0');
|
|
62
62
|
});
|
|
63
63
|
|
|
64
|
-
it('
|
|
64
|
+
it('renderiza el contenedor progress-circular para la variante circular', async () => {
|
|
65
65
|
el.variant = 'circular';
|
|
66
66
|
await el.updateComplete;
|
|
67
67
|
const progress = el.shadowRoot?.querySelector('[role="progressbar"]');
|
|
68
68
|
expect(progress?.classList.contains('progress-circular')).toBe(true);
|
|
69
69
|
});
|
|
70
70
|
|
|
71
|
-
it('
|
|
71
|
+
it('renderiza circle wavy para la variante circular-wavy', async () => {
|
|
72
72
|
el.variant = 'circular-wavy';
|
|
73
73
|
await el.updateComplete;
|
|
74
74
|
const progress = el.shadowRoot?.querySelector('[role="progressbar"]');
|
|
75
75
|
expect(progress?.classList.contains('progress-circular')).toBe(true);
|
|
76
76
|
});
|
|
77
77
|
|
|
78
|
-
it('
|
|
78
|
+
it('renderiza el contenedor progress-wavy para la variante wavy', async () => {
|
|
79
79
|
el.variant = 'wavy';
|
|
80
80
|
await el.updateComplete;
|
|
81
81
|
const progress = el.shadowRoot?.querySelector('[role="progressbar"]');
|
|
82
82
|
expect(progress?.classList.contains('progress-wavy')).toBe(true);
|
|
83
83
|
});
|
|
84
84
|
|
|
85
|
-
it('
|
|
85
|
+
it('refleja el atributo size', async () => {
|
|
86
86
|
el.size = 'large';
|
|
87
87
|
await el.updateComplete;
|
|
88
88
|
expect(el.getAttribute('size')).toBe('large');
|