@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
|
@@ -10,50 +10,50 @@ import { customElement, property } from 'lit/decorators.js';
|
|
|
10
10
|
import { MoniElement, sharedStyles } from './_base/index.js';
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
-
* Material Design 3 Tabs container
|
|
13
|
+
* Componente Material Design 3 Tabs container (Contenedor de pestañas).
|
|
14
14
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
15
|
+
* Un contenedor de navegación que agrupa múltiples elementos `<moni-tab>`. Las pestañas
|
|
16
|
+
* organizan el contenido en categorías de alto nivel y permiten al usuario alternar
|
|
17
|
+
* entre ellas.
|
|
18
18
|
*
|
|
19
|
-
* **
|
|
19
|
+
* **Referencia a la especificación M3:** `m3-docs/components/tabs/specs.md`
|
|
20
20
|
*
|
|
21
|
-
* **
|
|
22
|
-
* - `primary` (
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
* - `secondary`:
|
|
26
|
-
*
|
|
21
|
+
* **Modos (Primario vs Secundario):**
|
|
22
|
+
* - `primary` (por defecto): Usado para navegación de nivel superior en la jerarquía más alta,
|
|
23
|
+
* a menudo colocado directamente debajo de una barra de aplicación superior (top app bar).
|
|
24
|
+
* Abarcan todo el ancho y presentan un indicador activo prominente.
|
|
25
|
+
* - `secondary`: Usado para jerarquías de contenido más profundas dentro de un área
|
|
26
|
+
* o página específica. Típicamente son más sutiles.
|
|
27
27
|
*
|
|
28
|
-
* **
|
|
29
|
-
* - `scrollable`:
|
|
30
|
-
*
|
|
31
|
-
* - `align`:
|
|
32
|
-
* `left`, `center`,
|
|
33
|
-
* - `vertical`:
|
|
28
|
+
* **Diseño y alineación:**
|
|
29
|
+
* - `scrollable`: Si el número de pestañas excede el ancho del contenedor, esto
|
|
30
|
+
* habilita el desplazamiento horizontal (`overflow-x: auto`) en lugar de aplastarlas.
|
|
31
|
+
* - `align`: Controla cómo se distribuyen las pestañas (`default` space-around,
|
|
32
|
+
* `left`, `center`, o `right`).
|
|
33
|
+
* - `vertical`: Apila el icono sobre la etiqueta de texto dentro de las pestañas hijas.
|
|
34
34
|
*
|
|
35
|
-
* **
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
35
|
+
* **Indicador Activo:**
|
|
36
|
+
* El atributo `indicator-size` permite personalizar el ancho del
|
|
37
|
+
* indicador de subrayado activo (`default` se ajusta al contenido de la pestaña, `min` es estrecho, `max`
|
|
38
|
+
* llena todo el ancho de la pestaña).
|
|
39
39
|
*
|
|
40
40
|
* @example
|
|
41
41
|
* ```html
|
|
42
|
-
* <!--
|
|
42
|
+
* <!-- Pestañas primarias, con desplazamiento (scrollable) -->
|
|
43
43
|
* <moni-tabs scrollable>
|
|
44
|
-
* <moni-tab active label="
|
|
45
|
-
* <moni-tab label="
|
|
46
|
-
* <moni-tab label="
|
|
44
|
+
* <moni-tab active label="Vuelos"></moni-tab>
|
|
45
|
+
* <moni-tab label="Viajes"></moni-tab>
|
|
46
|
+
* <moni-tab label="Explorar"></moni-tab>
|
|
47
47
|
* </moni-tabs>
|
|
48
48
|
*
|
|
49
|
-
* <!--
|
|
49
|
+
* <!-- Pestañas secundarias, centradas con diseño vertical -->
|
|
50
50
|
* <moni-tabs mode="secondary" align="center" vertical>
|
|
51
51
|
* <moni-tab active icon="video_camera_front" label="Video"></moni-tab>
|
|
52
|
-
* <moni-tab icon="photo_camera" label="
|
|
52
|
+
* <moni-tab icon="photo_camera" label="Foto"></moni-tab>
|
|
53
53
|
* </moni-tabs>
|
|
54
54
|
* ```
|
|
55
55
|
*
|
|
56
|
-
* @slot default - `<moni-tab
|
|
56
|
+
* @slot default - Elementos hijos `<moni-tab>`.
|
|
57
57
|
*/
|
|
58
58
|
@customElement('moni-tabs')
|
|
59
59
|
export class MoniTabs extends MoniElement {
|
|
@@ -106,6 +106,12 @@ export class MoniTabs extends MoniElement {
|
|
|
106
106
|
`
|
|
107
107
|
];
|
|
108
108
|
|
|
109
|
+
/**
|
|
110
|
+
* Renderiza el contenedor de navegación.
|
|
111
|
+
* Construye dinámicamente las clases CSS que habilitan los selectores estructurales
|
|
112
|
+
* (`mode`, `align`, `indicatorSize`) permitiendo que el componente hijo `moni-tab`
|
|
113
|
+
* herede estilos contextuales sin necesidad de inyectar variables complejas.
|
|
114
|
+
*/
|
|
109
115
|
override render() {
|
|
110
116
|
const classes = [
|
|
111
117
|
'tabs',
|
|
@@ -14,7 +14,7 @@ describe('moni-text-field', () => {
|
|
|
14
14
|
el.remove();
|
|
15
15
|
});
|
|
16
16
|
|
|
17
|
-
it('
|
|
17
|
+
it('renderiza un contenedor de campo (field wrapper) y un input', async () => {
|
|
18
18
|
await el.updateComplete;
|
|
19
19
|
const field = el.shadowRoot?.querySelector('.field');
|
|
20
20
|
const input = el.shadowRoot?.querySelector('input');
|
|
@@ -22,49 +22,49 @@ describe('moni-text-field', () => {
|
|
|
22
22
|
expect(input).toBeTruthy();
|
|
23
23
|
});
|
|
24
24
|
|
|
25
|
-
it('
|
|
25
|
+
it('renderiza un icono inicial (leading) cuando se establece el atributo icon', async () => {
|
|
26
26
|
el.icon = 'search';
|
|
27
27
|
await el.updateComplete;
|
|
28
28
|
const leading = el.shadowRoot?.querySelector('.leading-icon');
|
|
29
29
|
expect(leading).toBeTruthy();
|
|
30
30
|
});
|
|
31
31
|
|
|
32
|
-
it('
|
|
32
|
+
it('renderiza un icono final (trailing) cuando se establece el atributo trailing-icon', async () => {
|
|
33
33
|
el.setAttribute('trailing-icon', 'close');
|
|
34
34
|
await el.updateComplete;
|
|
35
35
|
const trailing = el.shadowRoot?.querySelector('.trailing-icon');
|
|
36
36
|
expect(trailing).toBeTruthy();
|
|
37
37
|
});
|
|
38
38
|
|
|
39
|
-
it('
|
|
39
|
+
it('renderiza un texto prefijo cuando se establece el atributo prefix', async () => {
|
|
40
40
|
el.prefix = 'https://';
|
|
41
41
|
await el.updateComplete;
|
|
42
42
|
const leading = el.shadowRoot?.querySelector('.leading-icon');
|
|
43
43
|
expect(leading?.textContent?.trim()).toBe('https://');
|
|
44
44
|
});
|
|
45
45
|
|
|
46
|
-
it('
|
|
46
|
+
it('renderiza un texto sufijo cuando se establece el atributo suffix', async () => {
|
|
47
47
|
el.suffix = '.com';
|
|
48
48
|
await el.updateComplete;
|
|
49
49
|
const trailing = el.shadowRoot?.querySelector('.trailing-icon');
|
|
50
50
|
expect(trailing?.textContent?.trim()).toBe('.com');
|
|
51
51
|
});
|
|
52
52
|
|
|
53
|
-
it('
|
|
53
|
+
it('aplica la clase square en el contenedor de campo para shape=no-round', async () => {
|
|
54
54
|
el.shape = 'no-round';
|
|
55
55
|
await el.updateComplete;
|
|
56
56
|
const field = el.shadowRoot?.querySelector('.field');
|
|
57
57
|
expect(field?.classList.contains('square')).toBe(true);
|
|
58
58
|
});
|
|
59
59
|
|
|
60
|
-
it('
|
|
60
|
+
it('aplica la clase round en el contenedor de campo para shape=round', async () => {
|
|
61
61
|
el.shape = 'round';
|
|
62
62
|
await el.updateComplete;
|
|
63
63
|
const field = el.shadowRoot?.querySelector('.field');
|
|
64
64
|
expect(field?.classList.contains('round')).toBe(true);
|
|
65
65
|
});
|
|
66
66
|
|
|
67
|
-
it('
|
|
67
|
+
it('no aplica la clase de forma (shape) en el contenedor de campo para shape=square', async () => {
|
|
68
68
|
el.shape = 'square';
|
|
69
69
|
await el.updateComplete;
|
|
70
70
|
const field = el.shadowRoot?.querySelector('.field');
|
|
@@ -72,7 +72,7 @@ describe('moni-text-field', () => {
|
|
|
72
72
|
expect(field?.classList.contains('round')).toBe(false);
|
|
73
73
|
});
|
|
74
74
|
|
|
75
|
-
it('
|
|
75
|
+
it('muestra el indicador de carga cuando loading es true', async () => {
|
|
76
76
|
el.loading = true;
|
|
77
77
|
await el.updateComplete;
|
|
78
78
|
const trailing = el.shadowRoot?.querySelector('.trailing-icon');
|
|
@@ -80,13 +80,13 @@ describe('moni-text-field', () => {
|
|
|
80
80
|
expect(progress).toBeTruthy();
|
|
81
81
|
});
|
|
82
82
|
|
|
83
|
-
it('
|
|
83
|
+
it('no renderiza un icono inicial por defecto', async () => {
|
|
84
84
|
await el.updateComplete;
|
|
85
85
|
const leading = el.shadowRoot?.querySelector('.leading-icon');
|
|
86
86
|
expect(leading).toBeFalsy();
|
|
87
87
|
});
|
|
88
88
|
|
|
89
|
-
it('
|
|
89
|
+
it('reenvía value al input', async () => {
|
|
90
90
|
el.value = 'hello world';
|
|
91
91
|
await el.updateComplete;
|
|
92
92
|
const input = el.shadowRoot?.querySelector(
|
|
@@ -95,14 +95,14 @@ describe('moni-text-field', () => {
|
|
|
95
95
|
expect(input.value).toBe('hello world');
|
|
96
96
|
});
|
|
97
97
|
|
|
98
|
-
it('
|
|
98
|
+
it('agrega la clase active al input cuando se establece el valor', async () => {
|
|
99
99
|
el.value = 'something';
|
|
100
100
|
await el.updateComplete;
|
|
101
101
|
const input = el.shadowRoot?.querySelector('input');
|
|
102
102
|
expect(input?.classList.contains('active')).toBe(true);
|
|
103
103
|
});
|
|
104
104
|
|
|
105
|
-
it('
|
|
105
|
+
it('renderiza el label y alterna la clase active basándose en el valor', async () => {
|
|
106
106
|
el.label = 'Email';
|
|
107
107
|
await el.updateComplete;
|
|
108
108
|
const label = el.shadowRoot?.querySelector('label');
|
|
@@ -10,70 +10,109 @@ import { customElement, property, query } from 'lit/decorators.js';
|
|
|
10
10
|
import { ifDefined } from 'lit/directives/if-defined.js';
|
|
11
11
|
import { classMap } from 'lit/directives/class-map.js';
|
|
12
12
|
import { MoniElement, sharedStyles, fieldStyles } from './_base/index.js';
|
|
13
|
+
import { emitMoniEvent } from '../utils/event-emitter.js';
|
|
13
14
|
import './moni-icon.js';
|
|
14
15
|
import './moni-progress.js';
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
|
-
* Material Design 3 Text Field
|
|
18
|
+
* Componente Material Design 3 Text Field (Campo de texto).
|
|
18
19
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* filled
|
|
22
|
-
* error
|
|
20
|
+
* Un campo de entrada con todas las funciones que envuelve un `<input>` nativo dentro de la
|
|
21
|
+
* estructura de campo M3 (clase `.field` de `fieldStyles`). Soporta etiquetas flotantes,
|
|
22
|
+
* variantes llenas (filled) y contorneadas (outlined), iconos iniciales/finales (leading/trailing),
|
|
23
|
+
* texto de ayuda y estados de error.
|
|
23
24
|
*
|
|
24
|
-
* **
|
|
25
|
+
* **Referencia a la especificación M3:** `m3-docs/components/text-fields/specs.md`
|
|
25
26
|
*
|
|
26
|
-
* **
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* 1.
|
|
30
|
-
* 2.
|
|
31
|
-
* 3.
|
|
32
|
-
* 4.
|
|
33
|
-
* 5. `<output>`
|
|
27
|
+
* **Arquitectura visual:**
|
|
28
|
+
* Utiliza `fieldStyles` para toda la estructura CSS del campo. El contenedor del campo
|
|
29
|
+
* es un `<div class="field [modifiers]">` que envuelve:
|
|
30
|
+
* 1. Icono inicial (leading) opcional.
|
|
31
|
+
* 2. Elemento `<input>` nativo.
|
|
32
|
+
* 3. `<label>` flotante (cuando se establece `label`).
|
|
33
|
+
* 4. Icono final (trailing) opcional o indicador de carga (spinner).
|
|
34
|
+
* 5. `<output>` para texto de ayuda/error.
|
|
34
35
|
*
|
|
35
|
-
* **
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
* - Submit the native form (the `<input name>` participates in form submission).
|
|
39
|
-
* - Listen to `change` or `input` events via standard DOM event handling.
|
|
40
|
-
* - Use a framework binding (e.g. `bind:value` in Svelte, `v-model` in Vue).
|
|
36
|
+
* **Sincronización de eventos:**
|
|
37
|
+
* Emite `moni-input` en cada tipeo y `moni-change` al consolidar el valor (blur/enter).
|
|
38
|
+
* El valor interno del componente (`this.value`) se mantiene sincronizado automáticamente.
|
|
41
39
|
*
|
|
42
40
|
* @example
|
|
43
41
|
* ```html
|
|
44
42
|
* <moni-text-field
|
|
45
|
-
* label="
|
|
43
|
+
* label="Dirección de correo"
|
|
46
44
|
* type="email"
|
|
47
45
|
* name="email"
|
|
48
46
|
* icon="mail"
|
|
49
47
|
* variant="outlined"
|
|
50
|
-
* helper="
|
|
48
|
+
* helper="Nunca compartiremos tu correo."
|
|
51
49
|
* ></moni-text-field>
|
|
52
50
|
*
|
|
53
51
|
* <moni-text-field
|
|
54
|
-
* label="
|
|
52
|
+
* label="Monto"
|
|
55
53
|
* type="number"
|
|
56
54
|
* prefix="$"
|
|
57
55
|
* error
|
|
58
|
-
* error-text="
|
|
56
|
+
* error-text="El valor debe ser positivo"
|
|
59
57
|
* ></moni-text-field>
|
|
60
58
|
* ```
|
|
61
59
|
*
|
|
62
|
-
* @csspart field -
|
|
63
|
-
* @csspart input -
|
|
64
|
-
* @csspart label -
|
|
65
|
-
* @csspart helper -
|
|
66
|
-
* @csspart error-output -
|
|
60
|
+
* @csspart field - El contenedor div `.field` exterior.
|
|
61
|
+
* @csspart input - El elemento `<input>` nativo.
|
|
62
|
+
* @csspart label - El elemento `<label>` flotante.
|
|
63
|
+
* @csspart helper - El elemento `<output>` de ayuda.
|
|
64
|
+
* @csspart error-output - El elemento `<output>` de error.
|
|
67
65
|
*/
|
|
68
66
|
@customElement('moni-text-field')
|
|
69
67
|
export class MoniTextField extends MoniElement {
|
|
68
|
+
static formAssociated = true;
|
|
69
|
+
private _internals: ElementInternals;
|
|
70
|
+
|
|
71
|
+
constructor() {
|
|
72
|
+
super();
|
|
73
|
+
this._internals = this.attachInternals();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* El nombre del input, enviado con los datos del formulario.
|
|
78
|
+
* @type {string}
|
|
79
|
+
*/
|
|
70
80
|
@property({ reflect: true }) name = '';
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* El texto de la etiqueta flotante.
|
|
84
|
+
* @type {string}
|
|
85
|
+
*/
|
|
71
86
|
@property({ reflect: true }) label = '';
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Variante visual del campo de texto.
|
|
90
|
+
* @type {'filled' | 'outlined'}
|
|
91
|
+
* @default 'filled'
|
|
92
|
+
*/
|
|
72
93
|
@property({ reflect: true }) variant: 'filled' | 'outlined' = 'filled';
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Define las dimensiones del campo de texto.
|
|
97
|
+
* @type {'small' | 'medium' | 'large' | 'extra'}
|
|
98
|
+
* @default 'medium'
|
|
99
|
+
*/
|
|
73
100
|
@property({ reflect: true })
|
|
74
101
|
size: 'small' | 'medium' | 'large' | 'extra' = 'medium';
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Forma del radio del borde (border-radius) del campo.
|
|
105
|
+
* @type {'round' | 'square' | 'no-round'}
|
|
106
|
+
* @default 'no-round'
|
|
107
|
+
*/
|
|
75
108
|
@property({ reflect: true })
|
|
76
109
|
shape: 'round' | 'square' | 'no-round' = 'no-round';
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* El tipo de input HTML nativo.
|
|
113
|
+
* @type {'text' | 'password' | 'email' | 'number' | 'tel' | 'url' | 'search'}
|
|
114
|
+
* @default 'text'
|
|
115
|
+
*/
|
|
77
116
|
@property({ reflect: true })
|
|
78
117
|
type:
|
|
79
118
|
| 'text'
|
|
@@ -83,29 +122,139 @@ export class MoniTextField extends MoniElement {
|
|
|
83
122
|
| 'tel'
|
|
84
123
|
| 'url'
|
|
85
124
|
| 'search' = 'text';
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Nombre del icono inicial (leading) (Material Symbols).
|
|
128
|
+
* @type {string}
|
|
129
|
+
*/
|
|
86
130
|
@property({ reflect: true }) icon = '';
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Nombre del icono final (trailing) (Material Symbols).
|
|
134
|
+
* @type {string}
|
|
135
|
+
*/
|
|
87
136
|
@property({ reflect: true, attribute: 'trailing-icon' }) trailingIcon = '';
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Prefijo de texto corto mostrado antes del valor del input.
|
|
140
|
+
* @type {string}
|
|
141
|
+
*/
|
|
88
142
|
@property({ reflect: true }) prefix = '';
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Sufijo de texto corto mostrado después del valor del input.
|
|
146
|
+
* @type {string}
|
|
147
|
+
*/
|
|
89
148
|
@property({ reflect: true }) suffix = '';
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Texto de ayuda mostrado debajo del campo.
|
|
152
|
+
* @type {string}
|
|
153
|
+
*/
|
|
90
154
|
@property({ reflect: true }) helper = '';
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Texto de error mostrado debajo del campo cuando `error` es true.
|
|
158
|
+
* Sobrescribe el texto de ayuda.
|
|
159
|
+
* @type {string}
|
|
160
|
+
*/
|
|
91
161
|
@property({ reflect: true, attribute: 'error-text' }) errorText = '';
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Si es true, establece el campo en un estado de error.
|
|
165
|
+
* @type {boolean}
|
|
166
|
+
*/
|
|
92
167
|
@property({ type: Boolean, reflect: true }) error = false;
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Si es true, muestra un indicador de carga (progreso lineal/circular) al final.
|
|
171
|
+
* @type {boolean}
|
|
172
|
+
*/
|
|
93
173
|
@property({ type: Boolean, reflect: true }) loading = false;
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Deshabilita el campo de texto.
|
|
177
|
+
* @type {boolean}
|
|
178
|
+
*/
|
|
94
179
|
@property({ type: Boolean, reflect: true }) disabled = false;
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* El valor actual del input.
|
|
183
|
+
* @type {string}
|
|
184
|
+
*/
|
|
95
185
|
@property({ reflect: true }) value = '';
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Texto de marcador de posición (placeholder) mostrado cuando el input está vacío y la etiqueta es flotante.
|
|
189
|
+
* @type {string}
|
|
190
|
+
*/
|
|
96
191
|
@property({ reflect: true }) placeholder = '';
|
|
97
192
|
|
|
98
193
|
@query('input') private _input!: HTMLInputElement;
|
|
99
194
|
|
|
195
|
+
/**
|
|
196
|
+
* Sincroniza imperativamente las propiedades DOM del `<input>` nativo después de cada actualización reactiva.
|
|
197
|
+
*
|
|
198
|
+
* Las vinculaciones `?value` y `?disabled` de Lit establecen *atributos* HTML, no *propiedades* DOM.
|
|
199
|
+
* Para un `<input>`, el atributo `value` solo establece el valor *inicial*; la propiedad DOM
|
|
200
|
+
* `input.value` refleja el valor actual tecleado por el usuario. Después de una actualización reactiva que
|
|
201
|
+
* cambia `this.value` (ej. reinicio programático), debemos escribir directamente a la propiedad
|
|
202
|
+
* DOM para sobrescribir lo que el usuario ha tecleado. Esto también es crítico para los consumidores
|
|
203
|
+
* de React y Vue que mutan la propiedad del Custom Element directamente, omitiendo el flujo
|
|
204
|
+
* de atributos de Lit.
|
|
205
|
+
*
|
|
206
|
+
* @param changed - Mapa de los nombres de propiedades a sus valores anteriores que causaron esta actualización.
|
|
207
|
+
*/
|
|
100
208
|
override updated(changed: Map<string, unknown>) {
|
|
101
209
|
if (this._input) {
|
|
102
|
-
if (changed.has('value'))
|
|
210
|
+
if (changed.has('value')) {
|
|
211
|
+
this._input.value = this.value;
|
|
212
|
+
this._internals?.setFormValue?.(this.value);
|
|
213
|
+
}
|
|
103
214
|
if (changed.has('disabled')) this._input.disabled = this.disabled;
|
|
104
215
|
}
|
|
105
216
|
}
|
|
106
217
|
|
|
218
|
+
private _handleInput(e: Event) {
|
|
219
|
+
const target = e.target as HTMLInputElement;
|
|
220
|
+
this.value = target.value;
|
|
221
|
+
emitMoniEvent(this, 'moni-input', {
|
|
222
|
+
detail: { value: this.value, originalEvent: e }
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
private _handleChange(e: Event) {
|
|
227
|
+
const target = e.target as HTMLInputElement;
|
|
228
|
+
this.value = target.value;
|
|
229
|
+
emitMoniEvent(this, 'moni-change', {
|
|
230
|
+
detail: { value: this.value, originalEvent: e }
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
|
|
107
234
|
static override styles = [sharedStyles, fieldStyles];
|
|
108
235
|
|
|
236
|
+
/**
|
|
237
|
+
* Renderiza el campo de texto con animación de etiqueta flotante, iconos iniciales/finales, y texto de ayuda.
|
|
238
|
+
*
|
|
239
|
+
* **Composición de `fieldClasses`:**
|
|
240
|
+
* - `field` — siempre presente; diseño base del campo.
|
|
241
|
+
* - `label` — habilita el comportamiento de la etiqueta flotante vía CSS.
|
|
242
|
+
* - `fill` / `border` — variante filled vs outlined.
|
|
243
|
+
* - `small` / `large` / `extra` — modificador de tamaño.
|
|
244
|
+
* - `prefix` — desplaza la etiqueta cuando hay un icono inicial (leading) presente.
|
|
245
|
+
* - `suffix` — reserva espacio final (trailing) para el icono/texto de sufijo.
|
|
246
|
+
* - `invalid` — aplica colores de error cuando `error=true` o falla la validación nativa.
|
|
247
|
+
*
|
|
248
|
+
* **Flotación de la etiqueta (Label float):**
|
|
249
|
+
* `isActive` es true cuando `value` no está vacío o se establece un `placeholder`.
|
|
250
|
+
* Los selectores CSS `.field.label input:focus ~ label`, `.field.label.active label`
|
|
251
|
+
* flotan la etiqueta a la parte superior del borde del campo. Este componente
|
|
252
|
+
* establece `isActive` para evitar que la etiqueta colapse cuando un valor está preestablecido.
|
|
253
|
+
*
|
|
254
|
+
* **Zonas inicial / final (Leading / trailing):**
|
|
255
|
+
* `hasLeading` y `hasTrailing` añaden condicionalmente las clases CSS `prefix`/`suffix`
|
|
256
|
+
* y renderizan el icono o los elementos de texto de prefijo/sufijo.
|
|
257
|
+
*/
|
|
109
258
|
override render() {
|
|
110
259
|
const hasLeading = Boolean(this.icon) || Boolean(this.prefix);
|
|
111
260
|
const hasTrailing =
|
|
@@ -166,6 +315,8 @@ export class MoniTextField extends MoniElement {
|
|
|
166
315
|
.value=${this.value}
|
|
167
316
|
name=${ifDefined(this.name || undefined)}
|
|
168
317
|
class=${isActive ? 'active' : ''}
|
|
318
|
+
@input=${this._handleInput}
|
|
319
|
+
@change=${this._handleChange}
|
|
169
320
|
/>
|
|
170
321
|
${this.label
|
|
171
322
|
? html`<label
|
|
@@ -14,7 +14,7 @@ describe('moni-textarea', () => {
|
|
|
14
14
|
el.remove();
|
|
15
15
|
});
|
|
16
16
|
|
|
17
|
-
it('
|
|
17
|
+
it('renderiza un contenedor de campo (field wrapper) y un textarea', async () => {
|
|
18
18
|
await el.updateComplete;
|
|
19
19
|
const field = el.shadowRoot?.querySelector('.field');
|
|
20
20
|
const textarea = el.shadowRoot?.querySelector('textarea');
|
|
@@ -22,35 +22,35 @@ describe('moni-textarea', () => {
|
|
|
22
22
|
expect(textarea).toBeTruthy();
|
|
23
23
|
});
|
|
24
24
|
|
|
25
|
-
it('
|
|
25
|
+
it('renderiza un icono inicial (leading) cuando se establece el atributo icon', async () => {
|
|
26
26
|
el.icon = 'edit';
|
|
27
27
|
await el.updateComplete;
|
|
28
28
|
const leading = el.shadowRoot?.querySelector('.leading-icon');
|
|
29
29
|
expect(leading).toBeTruthy();
|
|
30
30
|
});
|
|
31
31
|
|
|
32
|
-
it('
|
|
32
|
+
it('renderiza un icono final (trailing) cuando se establece el atributo trailing-icon', async () => {
|
|
33
33
|
el.setAttribute('trailing-icon', 'send');
|
|
34
34
|
await el.updateComplete;
|
|
35
35
|
const trailing = el.shadowRoot?.querySelector('.trailing-icon');
|
|
36
36
|
expect(trailing).toBeTruthy();
|
|
37
37
|
});
|
|
38
38
|
|
|
39
|
-
it('
|
|
39
|
+
it('renderiza un texto prefijo cuando se establece el atributo prefix', async () => {
|
|
40
40
|
el.prefix = '~';
|
|
41
41
|
await el.updateComplete;
|
|
42
42
|
const leading = el.shadowRoot?.querySelector('.leading-icon');
|
|
43
43
|
expect(leading?.textContent?.trim()).toBe('~');
|
|
44
44
|
});
|
|
45
45
|
|
|
46
|
-
it('
|
|
46
|
+
it('renderiza un texto sufijo cuando se establece el atributo suffix', async () => {
|
|
47
47
|
el.suffix = 'chars';
|
|
48
48
|
await el.updateComplete;
|
|
49
49
|
const trailing = el.shadowRoot?.querySelector('.trailing-icon');
|
|
50
50
|
expect(trailing?.textContent?.trim()).toBe('chars');
|
|
51
51
|
});
|
|
52
52
|
|
|
53
|
-
it('
|
|
53
|
+
it('muestra el indicador de carga cuando loading es true', async () => {
|
|
54
54
|
el.loading = true;
|
|
55
55
|
await el.updateComplete;
|
|
56
56
|
const trailing = el.shadowRoot?.querySelector('.trailing-icon');
|
|
@@ -58,7 +58,7 @@ describe('moni-textarea', () => {
|
|
|
58
58
|
expect(progress).toBeTruthy();
|
|
59
59
|
});
|
|
60
60
|
|
|
61
|
-
it('
|
|
61
|
+
it('reenvía el atributo rows al textarea', async () => {
|
|
62
62
|
el.rows = 5;
|
|
63
63
|
await el.updateComplete;
|
|
64
64
|
const textarea = el.shadowRoot?.querySelector(
|
|
@@ -67,7 +67,7 @@ describe('moni-textarea', () => {
|
|
|
67
67
|
expect(textarea.rows).toBe(5);
|
|
68
68
|
});
|
|
69
69
|
|
|
70
|
-
it('
|
|
70
|
+
it('reenvía value al textarea', async () => {
|
|
71
71
|
el.value = 'multi\nline\ntext';
|
|
72
72
|
await el.updateComplete;
|
|
73
73
|
const textarea = el.shadowRoot?.querySelector(
|
|
@@ -76,28 +76,28 @@ describe('moni-textarea', () => {
|
|
|
76
76
|
expect(textarea.value).toBe('multi\nline\ntext');
|
|
77
77
|
});
|
|
78
78
|
|
|
79
|
-
it('
|
|
79
|
+
it('agrega la clase active al textarea cuando se establece el valor', async () => {
|
|
80
80
|
el.value = 'content';
|
|
81
81
|
await el.updateComplete;
|
|
82
82
|
const textarea = el.shadowRoot?.querySelector('textarea');
|
|
83
83
|
expect(textarea?.classList.contains('active')).toBe(true);
|
|
84
84
|
});
|
|
85
85
|
|
|
86
|
-
it('
|
|
86
|
+
it('aplica la clase square en el contenedor de campo para shape=no-round', async () => {
|
|
87
87
|
el.shape = 'no-round';
|
|
88
88
|
await el.updateComplete;
|
|
89
89
|
const field = el.shadowRoot?.querySelector('.field');
|
|
90
90
|
expect(field?.classList.contains('square')).toBe(true);
|
|
91
91
|
});
|
|
92
92
|
|
|
93
|
-
it('
|
|
93
|
+
it('aplica la clase round en el contenedor de campo para shape=round', async () => {
|
|
94
94
|
el.shape = 'round';
|
|
95
95
|
await el.updateComplete;
|
|
96
96
|
const field = el.shadowRoot?.querySelector('.field');
|
|
97
97
|
expect(field?.classList.contains('round')).toBe(true);
|
|
98
98
|
});
|
|
99
99
|
|
|
100
|
-
it('
|
|
100
|
+
it('no aplica la clase de forma (shape) en el contenedor de campo para shape=square', async () => {
|
|
101
101
|
el.shape = 'square';
|
|
102
102
|
await el.updateComplete;
|
|
103
103
|
const field = el.shadowRoot?.querySelector('.field');
|
|
@@ -107,20 +107,20 @@ describe('moni-textarea', () => {
|
|
|
107
107
|
|
|
108
108
|
// ─── P3.3: maxlength + character counter ───
|
|
109
109
|
|
|
110
|
-
it('
|
|
110
|
+
it('no renderiza un contador por defecto', async () => {
|
|
111
111
|
await el.updateComplete;
|
|
112
112
|
const counter = el.shadowRoot?.querySelector('.counter');
|
|
113
113
|
expect(counter).toBeFalsy();
|
|
114
114
|
});
|
|
115
115
|
|
|
116
|
-
it('
|
|
116
|
+
it('renderiza un contador cuando se establece maxlength', async () => {
|
|
117
117
|
el.maxlength = 100;
|
|
118
118
|
await el.updateComplete;
|
|
119
119
|
const counter = el.shadowRoot?.querySelector('.counter');
|
|
120
120
|
expect(counter).toBeTruthy();
|
|
121
121
|
});
|
|
122
122
|
|
|
123
|
-
it('
|
|
123
|
+
it('el contador muestra value.length / maxlength', async () => {
|
|
124
124
|
el.maxlength = 100;
|
|
125
125
|
el.value = 'Hello';
|
|
126
126
|
await el.updateComplete;
|
|
@@ -128,7 +128,7 @@ describe('moni-textarea', () => {
|
|
|
128
128
|
expect(counter?.textContent?.trim()).toBe('5 / 100');
|
|
129
129
|
});
|
|
130
130
|
|
|
131
|
-
it('no-counter
|
|
131
|
+
it('no-counter suprime el contador incluso cuando maxlength está establecido', async () => {
|
|
132
132
|
el.maxlength = 100;
|
|
133
133
|
el.noCounter = true;
|
|
134
134
|
await el.updateComplete;
|
|
@@ -136,7 +136,7 @@ describe('moni-textarea', () => {
|
|
|
136
136
|
expect(counter).toBeFalsy();
|
|
137
137
|
});
|
|
138
138
|
|
|
139
|
-
it('
|
|
139
|
+
it('reenvía maxlength al textarea interno como maxLength', async () => {
|
|
140
140
|
el.maxlength = 50;
|
|
141
141
|
await el.updateComplete;
|
|
142
142
|
const textarea = el.shadowRoot?.querySelector(
|