@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
|
@@ -10,46 +10,46 @@ import { customElement, property } from 'lit/decorators.js';
|
|
|
10
10
|
import { MoniElement, sharedStyles } from './_base/index.js';
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
-
* Material Design 3 Top App Bar (
|
|
13
|
+
* Componente Material Design 3 Top App Bar (Barra de herramientas superior).
|
|
14
14
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
15
|
+
* Las barras de aplicación superiores muestran información y acciones en la parte superior de una pantalla.
|
|
16
|
+
* Se utilizan para identidad de marca, títulos de pantalla, navegación y acciones.
|
|
17
17
|
*
|
|
18
|
-
* **
|
|
18
|
+
* **Referencia a la especificación M3:** `m3-docs/components/top-app-bar/specs.md`
|
|
19
19
|
*
|
|
20
|
-
* **
|
|
21
|
-
*
|
|
20
|
+
* **Nota:** Esta es la barra de herramientas estándar de nivel superior. Para barras de navegación
|
|
21
|
+
* inferiores (a menudo usadas en móviles), usa `<moni-app-bar>`.
|
|
22
22
|
*
|
|
23
|
-
* **
|
|
24
|
-
* - `standard` (
|
|
25
|
-
*
|
|
26
|
-
* - `floating`:
|
|
27
|
-
*
|
|
23
|
+
* **Variantes:**
|
|
24
|
+
* - `standard` (por defecto): Una barra de ancho completo (altura de 64dp) que se asienta al ras
|
|
25
|
+
* contra la parte superior de la pantalla.
|
|
26
|
+
* - `floating`: Una barra separada con un margen de 4dp y esquinas redondeadas de 8dp,
|
|
27
|
+
* que parece flotar sobre el contenido.
|
|
28
28
|
*
|
|
29
|
-
* **
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
29
|
+
* **Comportamiento de desplazamiento (scroll):**
|
|
30
|
+
* Cuando el atributo `scroll` está presente, la barra de herramientas responde visualmente al
|
|
31
|
+
* desplazamiento aumentando su elevación (sombra) y cambiando dinámicamente
|
|
32
|
+
* su color de superficie para indicar profundidad sobre el contenido desplazado.
|
|
33
33
|
*
|
|
34
34
|
* @example
|
|
35
35
|
* ```html
|
|
36
|
-
* <!--
|
|
37
|
-
* <moni-toolbar title="
|
|
36
|
+
* <!-- Barra de herramientas estándar con navegación y acciones -->
|
|
37
|
+
* <moni-toolbar title="Bandeja de entrada">
|
|
38
38
|
* <moni-icon-button slot="leading" icon="menu"></moni-icon-button>
|
|
39
39
|
* <moni-icon-button slot="trailing" icon="search"></moni-icon-button>
|
|
40
40
|
* <moni-icon-button slot="trailing" icon="more_vert"></moni-icon-button>
|
|
41
41
|
* </moni-toolbar>
|
|
42
42
|
*
|
|
43
|
-
* <!--
|
|
44
|
-
* <moni-toolbar type="floating" title="
|
|
43
|
+
* <!-- Barra de herramientas flotante con un FAB adjunto -->
|
|
44
|
+
* <moni-toolbar type="floating" title="Notas">
|
|
45
45
|
* <moni-fab slot="action-button" icon="add"></moni-fab>
|
|
46
46
|
* </moni-toolbar>
|
|
47
47
|
* ```
|
|
48
48
|
*
|
|
49
|
-
* @slot default -
|
|
50
|
-
* @slot leading -
|
|
51
|
-
* @slot trailing -
|
|
52
|
-
* @slot action-button -
|
|
49
|
+
* @slot default - El texto del título o contenido central.
|
|
50
|
+
* @slot leading - Icono/botón de navegación colocado en el extremo izquierdo.
|
|
51
|
+
* @slot trailing - Iconos/botones de acción colocados en el extremo derecho.
|
|
52
|
+
* @slot action-button - Un botón de acción flotante (FAB) anclado al lado derecho.
|
|
53
53
|
*/
|
|
54
54
|
@customElement('moni-toolbar')
|
|
55
55
|
export class MoniToolbar extends MoniElement {
|
|
@@ -123,6 +123,20 @@ export class MoniToolbar extends MoniElement {
|
|
|
123
123
|
`
|
|
124
124
|
];
|
|
125
125
|
|
|
126
|
+
/**
|
|
127
|
+
* Renderiza el diseño `<header>` de 3 zonas de la barra de herramientas.
|
|
128
|
+
*
|
|
129
|
+
* **Zonas:**
|
|
130
|
+
* - `.leading` — slot inicial para iconos de navegación o controles de migas de pan (breadcrumb).
|
|
131
|
+
* - `.title` — zona del título central; renderiza `this.title` como texto si el atributo
|
|
132
|
+
* está configurado, de lo contrario recurre al slot por defecto para contenido rico.
|
|
133
|
+
* - `.trailing` — slot final para iconos de acción (buscar, más, etc.).
|
|
134
|
+
*
|
|
135
|
+
* **Slot `action-button`:**
|
|
136
|
+
* Un slot nombrado separado, fuera del `<header>`, para un botón de acción flotante
|
|
137
|
+
* (FAB) o disparador de menú contextual que no debe participar en el diseño
|
|
138
|
+
* flex de la fila del título.
|
|
139
|
+
*/
|
|
126
140
|
override render() {
|
|
127
141
|
return html`
|
|
128
142
|
<header class="container" part="container">
|
|
@@ -18,24 +18,24 @@ describe('moni-tooltip (P3.1)', () => {
|
|
|
18
18
|
parent.remove();
|
|
19
19
|
});
|
|
20
20
|
|
|
21
|
-
it('
|
|
21
|
+
it('renderiza role="tooltip" en el elemento interno (accesibilidad M3)', async () => {
|
|
22
22
|
await el.updateComplete;
|
|
23
23
|
const tip = el.shadowRoot?.querySelector('[role="tooltip"]');
|
|
24
24
|
expect(tip).toBeTruthy();
|
|
25
25
|
});
|
|
26
26
|
|
|
27
|
-
it('
|
|
27
|
+
it('refleja el texto en el host', async () => {
|
|
28
28
|
await el.updateComplete;
|
|
29
29
|
expect(el.text).toBe('Save changes');
|
|
30
30
|
});
|
|
31
31
|
|
|
32
|
-
it('
|
|
32
|
+
it('refleja la posición (top por defecto)', async () => {
|
|
33
33
|
await el.updateComplete;
|
|
34
34
|
const tip = el.shadowRoot?.querySelector('.tooltip');
|
|
35
35
|
expect(tip?.classList.contains('top')).toBe(true);
|
|
36
36
|
});
|
|
37
37
|
|
|
38
|
-
it('
|
|
38
|
+
it('acepta los 6 posicionamientos M3 (top/top-start/top-end/bottom/bottom-start/bottom-end)', async () => {
|
|
39
39
|
const positions: Array<'top' | 'top-start' | 'top-end' | 'bottom' | 'bottom-start' | 'bottom-end'> = [
|
|
40
40
|
'top',
|
|
41
41
|
'top-start',
|
|
@@ -52,20 +52,20 @@ describe('moni-tooltip (P3.1)', () => {
|
|
|
52
52
|
}
|
|
53
53
|
});
|
|
54
54
|
|
|
55
|
-
it('
|
|
55
|
+
it('es plano (plain) por defecto (rich=false)', async () => {
|
|
56
56
|
await el.updateComplete;
|
|
57
57
|
expect(el.rich).toBe(false);
|
|
58
58
|
expect(el.hasAttribute('rich')).toBe(false);
|
|
59
59
|
});
|
|
60
60
|
|
|
61
|
-
it('rich=true
|
|
61
|
+
it('rich=true habilita el modo de contenido enriquecido (atributo rich reflejado)', async () => {
|
|
62
62
|
el.rich = true;
|
|
63
63
|
await el.updateComplete;
|
|
64
64
|
expect(el.rich).toBe(true);
|
|
65
65
|
expect(el.hasAttribute('rich')).toBe(true);
|
|
66
66
|
});
|
|
67
67
|
|
|
68
|
-
it('
|
|
68
|
+
it('muestra el tooltip en mouseenter y lo oculta en mouseleave', async () => {
|
|
69
69
|
await el.updateComplete;
|
|
70
70
|
const tip = el.shadowRoot?.querySelector('.tooltip') as HTMLElement;
|
|
71
71
|
expect(tip?.classList.contains('visible')).toBe(false);
|
|
@@ -79,7 +79,7 @@ describe('moni-tooltip (P3.1)', () => {
|
|
|
79
79
|
expect(tip?.classList.contains('visible')).toBe(false);
|
|
80
80
|
});
|
|
81
81
|
|
|
82
|
-
it('
|
|
82
|
+
it('muestra el tooltip en focusin y lo oculta en focusout', async () => {
|
|
83
83
|
await el.updateComplete;
|
|
84
84
|
const tip = el.shadowRoot?.querySelector('.tooltip') as HTMLElement;
|
|
85
85
|
parent.dispatchEvent(new FocusEvent('focusin', { bubbles: true }));
|
|
@@ -91,7 +91,7 @@ describe('moni-tooltip (P3.1)', () => {
|
|
|
91
91
|
expect(tip?.classList.contains('visible')).toBe(false);
|
|
92
92
|
});
|
|
93
93
|
|
|
94
|
-
it('Escape
|
|
94
|
+
it('la tecla Escape cierra un tooltip visible', async () => {
|
|
95
95
|
await el.updateComplete;
|
|
96
96
|
const tip = el.shadowRoot?.querySelector('.tooltip') as HTMLElement;
|
|
97
97
|
parent.dispatchEvent(new MouseEvent('mouseenter', { bubbles: true }));
|
|
@@ -103,20 +103,20 @@ describe('moni-tooltip (P3.1)', () => {
|
|
|
103
103
|
expect(tip?.classList.contains('visible')).toBe(false);
|
|
104
104
|
});
|
|
105
105
|
|
|
106
|
-
it('
|
|
106
|
+
it('aplica las variantes de tamaño (small/medium/large)', async () => {
|
|
107
107
|
for (const size of ['small', 'medium', 'large'] as const) {
|
|
108
108
|
el.size = size;
|
|
109
109
|
await el.updateComplete;
|
|
110
110
|
const tip = el.shadowRoot?.querySelector('.tooltip');
|
|
111
|
-
expect(tip?.classList.contains(size), `
|
|
111
|
+
expect(tip?.classList.contains(size), `esperada clase ${size}`).toBe(true);
|
|
112
112
|
}
|
|
113
113
|
});
|
|
114
114
|
|
|
115
|
-
it('
|
|
116
|
-
//
|
|
115
|
+
it('limpia los listeners al desconectarse', () => {
|
|
116
|
+
// Sanidad: remover el padre limpia todo.
|
|
117
117
|
parent.remove();
|
|
118
|
-
// No
|
|
119
|
-
//
|
|
118
|
+
// No se necesita aserción; si los listeners se fugaran, el siguiente beforeEach
|
|
119
|
+
// acumularía listeners pero vitest pasaría. Solo cobertura visual.
|
|
120
120
|
expect(parent.isConnected).toBe(false);
|
|
121
121
|
});
|
|
122
122
|
});
|
|
@@ -10,62 +10,72 @@ import { customElement, property } from 'lit/decorators.js';
|
|
|
10
10
|
import { MoniElement, sharedStyles } from './_base/index.js';
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
-
* Material Design 3 Tooltip
|
|
13
|
+
* Componente Material Design 3 Tooltip (Información sobre herramientas).
|
|
14
14
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
15
|
+
* Los tooltips proporcionan etiquetas de texto contextual o contenido enriquecido que aparecen cuando
|
|
16
|
+
* los usuarios pasan el cursor por encima, enfocan o tocan un elemento. Muestran información
|
|
17
|
+
* complementaria que ayuda a los usuarios a entender los elementos de la interfaz sin
|
|
18
|
+
* ocupar permanentemente espacio en la pantalla.
|
|
19
19
|
*
|
|
20
|
-
* **
|
|
20
|
+
* **Referencia a la especificación M3:** `m3-docs/components/tooltips/specs.md`
|
|
21
21
|
*
|
|
22
|
-
* **
|
|
23
|
-
* - **Plain** (
|
|
24
|
-
* - **Rich** (`rich`
|
|
25
|
-
*
|
|
22
|
+
* **Tipos:**
|
|
23
|
+
* - **Plain** (por defecto) — Etiqueta solo de texto para descripciones simples (máx. 1 línea).
|
|
24
|
+
* - **Rich** (atributo `rich`) — Contenido HTML que incluye texto formateado,
|
|
25
|
+
* enlaces e iconos. Los tooltips enriquecidos pueden contener múltiples líneas y enlaces de acción.
|
|
26
26
|
*
|
|
27
|
-
* **Placements:**
|
|
28
|
-
* - `top` (
|
|
27
|
+
* **Ubicaciones (Placements):**
|
|
28
|
+
* - `top` (por defecto), `top-start`, `top-end`
|
|
29
29
|
* - `bottom`, `bottom-start`, `bottom-end`
|
|
30
30
|
*
|
|
31
|
-
* **Trigger
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
* `:focus-within`
|
|
31
|
+
* **Mecanismo de activación (Trigger):**
|
|
32
|
+
* El tooltip usa `position: absolute` dentro del elemento padre. El padre
|
|
33
|
+
* debe tener `position: relative` (establecido automáticamente vía `connectedCallback`).
|
|
34
|
+
* Los eventos hover/focus en el padre activan los selectores CSS `:hover` y
|
|
35
|
+
* `:focus-within` del tooltip, los cuales impulsan la transición de mostrar/ocultar.
|
|
36
36
|
*
|
|
37
|
-
* **
|
|
38
|
-
* -
|
|
39
|
-
* -
|
|
40
|
-
*
|
|
41
|
-
* `tooltipId`
|
|
42
|
-
* -
|
|
37
|
+
* **Accesibilidad:**
|
|
38
|
+
* - El tooltip tiene `role="tooltip"`.
|
|
39
|
+
* - Para accesibilidad por teclado, el padre debe tener `aria-describedby`
|
|
40
|
+
* apuntando al atributo `id` del tooltip. El componente expone un
|
|
41
|
+
* getter `tooltipId` para este propósito.
|
|
42
|
+
* - La tecla `Escape` cierra los tooltips enriquecidos.
|
|
43
43
|
*
|
|
44
44
|
* @example
|
|
45
45
|
* ```html
|
|
46
|
-
* <!-- Plain
|
|
46
|
+
* <!-- Tooltip simple (Plain) -->
|
|
47
47
|
* <button aria-describedby="save-tip">
|
|
48
|
-
*
|
|
48
|
+
* Guardar
|
|
49
49
|
* <moni-tooltip id="save-tip" text="Ctrl+S"></moni-tooltip>
|
|
50
50
|
* </button>
|
|
51
51
|
*
|
|
52
|
-
* <!-- Rich
|
|
52
|
+
* <!-- Tooltip enriquecido (Rich) -->
|
|
53
53
|
* <button>
|
|
54
|
-
*
|
|
54
|
+
* Filtrar
|
|
55
55
|
* <moni-tooltip rich position="bottom">
|
|
56
|
-
* <strong>
|
|
57
|
-
* <p>
|
|
56
|
+
* <strong>Filtrar por fecha</strong>
|
|
57
|
+
* <p>Selecciona un rango de fechas para filtrar resultados.</p>
|
|
58
58
|
* </moni-tooltip>
|
|
59
59
|
* </button>
|
|
60
60
|
* ```
|
|
61
61
|
*
|
|
62
|
-
* @slot default -
|
|
62
|
+
* @slot default - Contenido enriquecido para el cuerpo del tooltip (solo usado cuando `rich=true`).
|
|
63
63
|
*
|
|
64
|
-
* @csspart tooltip -
|
|
64
|
+
* @csspart tooltip - El elemento contenedor del tooltip.
|
|
65
65
|
*/
|
|
66
66
|
@customElement('moni-tooltip')
|
|
67
67
|
export class MoniTooltip extends MoniElement {
|
|
68
|
+
/**
|
|
69
|
+
* Contenido de texto simple para mostrar. Utilizado cuando `rich` es falso.
|
|
70
|
+
* @type {string}
|
|
71
|
+
*/
|
|
68
72
|
@property({ reflect: true }) text = '';
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Ubicación preferida relativa al ancla/activador.
|
|
76
|
+
* @type {'top' | 'top-start' | 'top-end' | 'bottom' | 'bottom-start' | 'bottom-end'}
|
|
77
|
+
* @default 'top'
|
|
78
|
+
*/
|
|
69
79
|
@property({ reflect: true })
|
|
70
80
|
position:
|
|
71
81
|
| 'top'
|
|
@@ -74,25 +84,47 @@ export class MoniTooltip extends MoniElement {
|
|
|
74
84
|
| 'bottom'
|
|
75
85
|
| 'bottom-start'
|
|
76
86
|
| 'bottom-end' = 'top';
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Mapeo de tamaño opcional (usado por hojas de estilo internas para escalar fuente/relleno).
|
|
90
|
+
* @type {'' | 'small' | 'medium' | 'large'}
|
|
91
|
+
* @default ''
|
|
92
|
+
*/
|
|
77
93
|
@property({ reflect: true })
|
|
78
94
|
size: '' | 'small' | 'medium' | 'large' = '';
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Si es true, cambia al modo de Tooltip Enriquecido (permite HTML/componentes en el slot por defecto).
|
|
98
|
+
* @type {boolean}
|
|
99
|
+
*/
|
|
79
100
|
@property({ type: Boolean, reflect: true }) rich = false;
|
|
80
101
|
|
|
81
102
|
private _target: HTMLElement | null = null;
|
|
82
103
|
private _tooltipEl: HTMLElement | null = null;
|
|
104
|
+
/**
|
|
105
|
+
* Wrapper estático para el evento de teclado global.
|
|
106
|
+
* Mantiene fijo el contexto léxico para registrar/desregistrar limpiamente.
|
|
107
|
+
*/
|
|
83
108
|
private _docKeydown = (e: KeyboardEvent) => this._handleDocKeydown(e);
|
|
84
109
|
/**
|
|
85
|
-
* CSS `anchor-name`
|
|
86
|
-
*
|
|
87
|
-
* `crypto.randomUUID()`
|
|
110
|
+
* Nombre de anclaje CSS (`anchor-name`) registrado en el activador padre para que el tooltip
|
|
111
|
+
* pueda usar `position-anchor` para vincularse a él. Generado por instancia vía
|
|
112
|
+
* `crypto.randomUUID()` cuando el posicionamiento de anclaje CSS está soportado.
|
|
88
113
|
*/
|
|
89
114
|
private _anchorName: string | null = null;
|
|
90
115
|
|
|
116
|
+
/**
|
|
117
|
+
* Hook de inicialización (Lit).
|
|
118
|
+
* Resuelve la asociación nativa con su elemento padre (trigger), forzando un contexto
|
|
119
|
+
* de posicionamiento relativo (`position: relative`) si es necesario. Vincula dinámicamente
|
|
120
|
+
* listeners de `mouseenter/leave` y `focusin/out` para controlar la visibilidad del globo.
|
|
121
|
+
* También auto-registra la revolucionaria CSS Anchor Positioning API si el navegador la soporta.
|
|
122
|
+
*/
|
|
91
123
|
override connectedCallback() {
|
|
92
124
|
super.connectedCallback();
|
|
93
125
|
this._target = this.parentElement;
|
|
94
126
|
if (this._target) {
|
|
95
|
-
//
|
|
127
|
+
// Asegura que el padre tenga position: relative para anclar el tooltip absoluto
|
|
96
128
|
const style = getComputedStyle(this._target);
|
|
97
129
|
if (style.position === 'static') {
|
|
98
130
|
this._target.style.position = 'relative';
|
|
@@ -102,9 +134,9 @@ export class MoniTooltip extends MoniElement {
|
|
|
102
134
|
this._target.addEventListener('mouseleave', this._hide);
|
|
103
135
|
this._target.addEventListener('focusout', this._hide);
|
|
104
136
|
|
|
105
|
-
// Auto-
|
|
106
|
-
//
|
|
107
|
-
//
|
|
137
|
+
// Auto-registra un nombre de ancla CSS en el activador padre cuando el
|
|
138
|
+
// navegador soporta posicionamiento de ancla. Los consumidores pueden excluirse
|
|
139
|
+
// estableciendo `data-no-anchor` en el activador.
|
|
108
140
|
const cssSupports = (globalThis as unknown as {
|
|
109
141
|
CSS?: { supports?: (k: string) => boolean };
|
|
110
142
|
}).CSS?.supports;
|
|
@@ -124,6 +156,11 @@ export class MoniTooltip extends MoniElement {
|
|
|
124
156
|
document.addEventListener('keydown', this._docKeydown);
|
|
125
157
|
}
|
|
126
158
|
|
|
159
|
+
/**
|
|
160
|
+
* Hook de destrucción (Lit).
|
|
161
|
+
* Remueve diligentemente todos los detectores de eventos del padre (trigger)
|
|
162
|
+
* y limpia las declaraciones generadas dinámicamente en estilos inline (`anchor-name`).
|
|
163
|
+
*/
|
|
127
164
|
override disconnectedCallback() {
|
|
128
165
|
if (this._target) {
|
|
129
166
|
this._target.removeEventListener('mouseenter', this._show);
|
|
@@ -139,6 +176,10 @@ export class MoniTooltip extends MoniElement {
|
|
|
139
176
|
super.disconnectedCallback();
|
|
140
177
|
}
|
|
141
178
|
|
|
179
|
+
/**
|
|
180
|
+
* Inyecta la clase activa (`.visible`) desencadenando la animación de opacidad/escalado.
|
|
181
|
+
* Cached-query: Recupera asíncronamente el tooltip del Shadow DOM si no lo había hecho.
|
|
182
|
+
*/
|
|
142
183
|
private _show = () => {
|
|
143
184
|
if (!this._tooltipEl) {
|
|
144
185
|
this._tooltipEl = this.shadowRoot?.querySelector('.tooltip') as HTMLElement;
|
|
@@ -148,6 +189,9 @@ export class MoniTooltip extends MoniElement {
|
|
|
148
189
|
}
|
|
149
190
|
};
|
|
150
191
|
|
|
192
|
+
/**
|
|
193
|
+
* Retira la clase activa (`.visible`), desvaneciendo el globo con gracia.
|
|
194
|
+
*/
|
|
151
195
|
private _hide = () => {
|
|
152
196
|
if (!this._tooltipEl) {
|
|
153
197
|
this._tooltipEl = this.shadowRoot?.querySelector('.tooltip') as HTMLElement;
|
|
@@ -157,6 +201,11 @@ export class MoniTooltip extends MoniElement {
|
|
|
157
201
|
}
|
|
158
202
|
};
|
|
159
203
|
|
|
204
|
+
/**
|
|
205
|
+
* Manejador global del teclado (a11y).
|
|
206
|
+
* Permite disipar instantáneamente el tooltip presionando `Escape`
|
|
207
|
+
* sin necesidad de mover el ratón o perder el foco.
|
|
208
|
+
*/
|
|
160
209
|
private _handleDocKeydown(e: KeyboardEvent) {
|
|
161
210
|
if (e.key !== 'Escape') return;
|
|
162
211
|
if (!this._tooltipEl?.classList.contains('visible')) return;
|
|
@@ -164,8 +213,8 @@ export class MoniTooltip extends MoniElement {
|
|
|
164
213
|
}
|
|
165
214
|
|
|
166
215
|
/**
|
|
167
|
-
*
|
|
168
|
-
*
|
|
216
|
+
* ID público del elemento tooltip, adecuado para `aria-describedby` en
|
|
217
|
+
* el padre activador. Generado automáticamente si el consumidor no estableció un `id`.
|
|
169
218
|
*/
|
|
170
219
|
get tooltipId(): string {
|
|
171
220
|
return this._tooltipEl?.id || '';
|
|
@@ -328,6 +377,24 @@ export class MoniTooltip extends MoniElement {
|
|
|
328
377
|
`
|
|
329
378
|
];
|
|
330
379
|
|
|
380
|
+
/**
|
|
381
|
+
* Renderiza el `<div>` del tooltip con su lista de clases calculada y atributos ARIA.
|
|
382
|
+
*
|
|
383
|
+
* **Composición de clases:**
|
|
384
|
+
* - `'tooltip'` — siempre presente; estilos base.
|
|
385
|
+
* - `this.position` — variante de ubicación (ej. `'top'`, `'bottom-start'`).
|
|
386
|
+
* - `this.size` — modificador de tamaño (`'small'`, `'medium'`, `'large'`).
|
|
387
|
+
*
|
|
388
|
+
* **CSS Anchor Positioning:**
|
|
389
|
+
* Si `_anchorName` está poblado, lo inyecta como la propiedad personalizada `--_anchor-name`.
|
|
390
|
+
* La declaración CSS `@anchor-name` conecta este tooltip a su elemento activador
|
|
391
|
+
* a través de la API CSS Anchor Positioning (Chrome 125+).
|
|
392
|
+
* En navegadores no compatibles, se utiliza un posicionamiento absoluto clásico como respaldo.
|
|
393
|
+
*
|
|
394
|
+
* **Respaldo de contenido:**
|
|
395
|
+
* El slot por defecto renderiza el contenido distribuido (slotted); si no hay hijos,
|
|
396
|
+
* el valor del atributo `text` se muestra como la etiqueta del tooltip.
|
|
397
|
+
*/
|
|
331
398
|
override render() {
|
|
332
399
|
const classes = [
|
|
333
400
|
'tooltip',
|
|
@@ -14,13 +14,13 @@ describe('moni-typography (P5.2 — recreated)', () => {
|
|
|
14
14
|
el.remove();
|
|
15
15
|
});
|
|
16
16
|
|
|
17
|
-
it('
|
|
17
|
+
it('variant=body, size=medium por defecto', async () => {
|
|
18
18
|
await el.updateComplete;
|
|
19
19
|
expect(el.variant).toBe('body');
|
|
20
20
|
expect(el.size).toBe('medium');
|
|
21
21
|
});
|
|
22
22
|
|
|
23
|
-
it('
|
|
23
|
+
it('renderiza la etiqueta <p> por defecto para la variante body', async () => {
|
|
24
24
|
el.text = 'Hello';
|
|
25
25
|
await el.updateComplete;
|
|
26
26
|
const el_tag = el.shadowRoot?.querySelector('p');
|
|
@@ -28,7 +28,7 @@ describe('moni-typography (P5.2 — recreated)', () => {
|
|
|
28
28
|
expect(el_tag?.textContent?.trim()).toBe('Hello');
|
|
29
29
|
});
|
|
30
30
|
|
|
31
|
-
it('
|
|
31
|
+
it('renderiza <h1> para la variante display', async () => {
|
|
32
32
|
el.variant = 'display';
|
|
33
33
|
el.text = 'Big text';
|
|
34
34
|
await el.updateComplete;
|
|
@@ -37,7 +37,7 @@ describe('moni-typography (P5.2 — recreated)', () => {
|
|
|
37
37
|
expect(h1?.classList.contains('display')).toBe(true);
|
|
38
38
|
});
|
|
39
39
|
|
|
40
|
-
it('
|
|
40
|
+
it('renderiza <h2> para la variante headline', async () => {
|
|
41
41
|
el.variant = 'headline';
|
|
42
42
|
el.text = 'Section';
|
|
43
43
|
await el.updateComplete;
|
|
@@ -46,21 +46,21 @@ describe('moni-typography (P5.2 — recreated)', () => {
|
|
|
46
46
|
expect(h2?.classList.contains('headline')).toBe(true);
|
|
47
47
|
});
|
|
48
48
|
|
|
49
|
-
it('
|
|
49
|
+
it('renderiza <h3> para la variante title', async () => {
|
|
50
50
|
el.variant = 'title';
|
|
51
51
|
await el.updateComplete;
|
|
52
52
|
const h3 = el.shadowRoot?.querySelector('h3');
|
|
53
53
|
expect(h3).toBeTruthy();
|
|
54
54
|
});
|
|
55
55
|
|
|
56
|
-
it('
|
|
56
|
+
it('renderiza <label> para la variante label', async () => {
|
|
57
57
|
el.variant = 'label';
|
|
58
58
|
await el.updateComplete;
|
|
59
59
|
const label = el.shadowRoot?.querySelector('label');
|
|
60
60
|
expect(label).toBeTruthy();
|
|
61
61
|
});
|
|
62
62
|
|
|
63
|
-
it('
|
|
63
|
+
it('sobrescribe la etiqueta mediante el atributo as', async () => {
|
|
64
64
|
el.variant = 'headline';
|
|
65
65
|
el.as = 'span';
|
|
66
66
|
await el.updateComplete;
|
|
@@ -69,7 +69,7 @@ describe('moni-typography (P5.2 — recreated)', () => {
|
|
|
69
69
|
expect(span?.classList.contains('headline')).toBe(true);
|
|
70
70
|
});
|
|
71
71
|
|
|
72
|
-
it('
|
|
72
|
+
it('refleja las variaciones de tamaño', async () => {
|
|
73
73
|
el.variant = 'title';
|
|
74
74
|
for (const size of ['large', 'medium', 'small'] as const) {
|
|
75
75
|
el.size = size;
|
|
@@ -79,7 +79,7 @@ describe('moni-typography (P5.2 — recreated)', () => {
|
|
|
79
79
|
}
|
|
80
80
|
});
|
|
81
81
|
|
|
82
|
-
it('
|
|
82
|
+
it('soporta las 5 variantes × 3 tamaños', async () => {
|
|
83
83
|
const variants: Array<'display' | 'headline' | 'title' | 'body' | 'label'> = [
|
|
84
84
|
'display',
|
|
85
85
|
'headline',
|
|
@@ -106,7 +106,7 @@ describe('moni-typography (P5.2 — recreated)', () => {
|
|
|
106
106
|
}
|
|
107
107
|
});
|
|
108
108
|
|
|
109
|
-
it('
|
|
109
|
+
it('renderiza el contenido del slot cuando el atributo text está vacío', async () => {
|
|
110
110
|
el.text = '';
|
|
111
111
|
el.textContent = 'Slotted content';
|
|
112
112
|
await el.updateComplete;
|