@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
|
@@ -14,14 +14,14 @@ describe('moni-snackbar', () => {
|
|
|
14
14
|
el.remove();
|
|
15
15
|
});
|
|
16
16
|
|
|
17
|
-
it('
|
|
17
|
+
it('renderiza un div con role=status y aria-live=polite (especificación M3)', async () => {
|
|
18
18
|
await el.updateComplete;
|
|
19
19
|
const snack = el.shadowRoot?.querySelector('[part="snackbar"]');
|
|
20
20
|
expect(snack?.getAttribute('role')).toBe('status');
|
|
21
21
|
expect(snack?.getAttribute('aria-live')).toBe('polite');
|
|
22
22
|
});
|
|
23
23
|
|
|
24
|
-
it('
|
|
24
|
+
it('refleja el atributo active en el host', async () => {
|
|
25
25
|
el.active = true;
|
|
26
26
|
await el.updateComplete;
|
|
27
27
|
expect(el.hasAttribute('active')).toBe(true);
|
|
@@ -31,7 +31,7 @@ describe('moni-snackbar', () => {
|
|
|
31
31
|
expect(el.hasAttribute('active')).toBe(false);
|
|
32
32
|
});
|
|
33
33
|
|
|
34
|
-
it('
|
|
34
|
+
it('refleja placement=bottom (por defecto) y placement=top', async () => {
|
|
35
35
|
await el.updateComplete;
|
|
36
36
|
const snack = el.shadowRoot?.querySelector('[part="snackbar"]');
|
|
37
37
|
expect(snack?.classList.contains('bottom')).toBe(true);
|
|
@@ -42,7 +42,7 @@ describe('moni-snackbar', () => {
|
|
|
42
42
|
expect(snack2?.classList.contains('top')).toBe(true);
|
|
43
43
|
});
|
|
44
44
|
|
|
45
|
-
it('
|
|
45
|
+
it('renderiza el texto en el span [part=text]', async () => {
|
|
46
46
|
el.text = 'File saved successfully';
|
|
47
47
|
await el.updateComplete;
|
|
48
48
|
const text = el.shadowRoot?.querySelector('[part="text"]');
|
|
@@ -53,7 +53,7 @@ describe('moni-snackbar', () => {
|
|
|
53
53
|
expect(t).toBe('File saved successfully');
|
|
54
54
|
});
|
|
55
55
|
|
|
56
|
-
it('
|
|
56
|
+
it('renderiza la etiqueta de acción cuando está establecida', async () => {
|
|
57
57
|
el.text = 'Item deleted';
|
|
58
58
|
el.action = 'Undo';
|
|
59
59
|
await el.updateComplete;
|
|
@@ -61,19 +61,19 @@ describe('moni-snackbar', () => {
|
|
|
61
61
|
expect(action?.textContent).toBe('Undo');
|
|
62
62
|
});
|
|
63
63
|
|
|
64
|
-
it('max-lines
|
|
64
|
+
it('max-lines es 2 por defecto (especificación M3)', async () => {
|
|
65
65
|
await el.updateComplete;
|
|
66
66
|
expect(el.maxLines).toBe(2);
|
|
67
67
|
expect(el.getAttribute('max-lines')).toBe('2');
|
|
68
68
|
});
|
|
69
69
|
|
|
70
|
-
it('max-lines
|
|
70
|
+
it('max-lines se puede personalizar mediante atributo', async () => {
|
|
71
71
|
el.maxLines = 3;
|
|
72
72
|
await el.updateComplete;
|
|
73
73
|
expect(el.getAttribute('max-lines')).toBe('3');
|
|
74
74
|
});
|
|
75
75
|
|
|
76
|
-
it('max-lines
|
|
76
|
+
it('max-lines se reenvía al elemento interno como una propiedad personalizada de CSS', async () => {
|
|
77
77
|
el.maxLines = 4;
|
|
78
78
|
await el.updateComplete;
|
|
79
79
|
const snack = el.shadowRoot?.querySelector('[part="snackbar"]') as HTMLElement;
|
|
@@ -11,76 +11,76 @@ import { MoniElement, sharedStyles } from './_base/index.js';
|
|
|
11
11
|
import './moni-icon.js';
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
|
-
* Material Design 3 Snackbar
|
|
14
|
+
* Componente Material Design 3 Snackbar (Barra de notificaciones).
|
|
15
15
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
16
|
+
* Los snackbars proporcionan mensajes breves sobre los procesos de la aplicación en la parte
|
|
17
|
+
* inferior de la pantalla. Desaparecen automáticamente y no requieren acción del usuario,
|
|
18
|
+
* pero pueden contener una única acción opcional.
|
|
19
19
|
*
|
|
20
|
-
* **
|
|
20
|
+
* **Referencia a la especificación M3:** `m3-docs/components/snackbar/specs.md`
|
|
21
21
|
*
|
|
22
|
-
* **
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
22
|
+
* **Modelo de posicionamiento:**
|
|
23
|
+
* El snackbar utiliza `position: fixed` para que se renderice en la ventana gráfica (viewport)
|
|
24
|
+
* independientemente del elemento en el que esté ubicado en el DOM. El elemento host
|
|
25
|
+
* se muestra como `block` en lugar de `contents` para asegurar que `position: fixed`
|
|
26
|
+
* dentro del shadow root se ancle a la ventana gráfica (no a un contexto de apilamiento
|
|
27
|
+
* creado por un ancestro transformado).
|
|
28
28
|
*
|
|
29
|
-
* **
|
|
30
|
-
*
|
|
31
|
-
* `opacity`, `visibility`,
|
|
32
|
-
*
|
|
29
|
+
* **Mecanismo de mostrar/ocultar:**
|
|
30
|
+
* La visibilidad es controlada por `:host([active]) .snackbar` a través de CSS
|
|
31
|
+
* `opacity`, `visibility`, y `transform`. Esto imita el patrón `.snackbar.active`
|
|
32
|
+
* de BeerCSS y permite animaciones de transición CSS.
|
|
33
33
|
*
|
|
34
|
-
* **
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
34
|
+
* **Truncamiento de texto M3:**
|
|
35
|
+
* El texto del mensaje se limita a `maxLines` líneas con `-webkit-line-clamp`.
|
|
36
|
+
* La especificación M3 requiere un máximo de 2 líneas; los consumidores pueden
|
|
37
|
+
* anular esto a través del atributo `max-lines`.
|
|
38
38
|
*
|
|
39
39
|
* @example
|
|
40
40
|
* ```ts
|
|
41
41
|
* const snackbar = document.querySelector('moni-snackbar') as MoniSnackbar;
|
|
42
42
|
*
|
|
43
|
-
* //
|
|
44
|
-
* snackbar.text = '
|
|
45
|
-
* snackbar.action = '
|
|
43
|
+
* // Mostrar por 3 segundos
|
|
44
|
+
* snackbar.text = 'Elemento eliminado';
|
|
45
|
+
* snackbar.action = 'Deshacer';
|
|
46
46
|
* snackbar.active = true;
|
|
47
47
|
* setTimeout(() => { snackbar.active = false; }, 3000);
|
|
48
48
|
* ```
|
|
49
49
|
*
|
|
50
|
-
* @slot default -
|
|
50
|
+
* @slot default - Contenido adicional colocado dentro del contenedor del snackbar.
|
|
51
51
|
*
|
|
52
|
-
* @csspart snackbar -
|
|
53
|
-
* @csspart text -
|
|
54
|
-
* @csspart action -
|
|
52
|
+
* @csspart snackbar - El elemento contenedor interno del snackbar.
|
|
53
|
+
* @csspart text - El elemento del texto del mensaje.
|
|
54
|
+
* @csspart action - El elemento del botón de acción.
|
|
55
55
|
*/
|
|
56
56
|
@customElement('moni-snackbar')
|
|
57
57
|
export class MoniSnackbar extends MoniElement {
|
|
58
58
|
/**
|
|
59
|
-
*
|
|
59
|
+
* El texto del mensaje principal mostrado en el snackbar.
|
|
60
60
|
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
61
|
+
* Limitado a `maxLines` líneas. Los mensajes largos se truncan con `…`.
|
|
62
|
+
* Según la especificación M3, mantenga los mensajes cortos e informativos (menos de 60 caracteres).
|
|
63
63
|
*
|
|
64
64
|
* @default ''
|
|
65
65
|
*/
|
|
66
66
|
@property({ reflect: true }) text = '';
|
|
67
67
|
|
|
68
68
|
/**
|
|
69
|
-
*
|
|
69
|
+
* Etiqueta para el botón de acción opcional.
|
|
70
70
|
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
71
|
+
* Cuando no está vacía, renderiza un botón de texto en el borde posterior (trailing) del snackbar.
|
|
72
|
+
* El componente despacha un evento `'action'` cuando se hace clic en la acción.
|
|
73
|
+
* Esta es una etiqueta puramente visual — el consumidor maneja la lógica de la acción.
|
|
74
74
|
*
|
|
75
75
|
* @default ''
|
|
76
76
|
*/
|
|
77
77
|
@property({ reflect: true }) action = '';
|
|
78
78
|
|
|
79
79
|
/**
|
|
80
|
-
*
|
|
80
|
+
* Ubicación vertical del snackbar en la pantalla.
|
|
81
81
|
*
|
|
82
|
-
* - `'bottom'` (
|
|
83
|
-
* - `'top'` —
|
|
82
|
+
* - `'bottom'` (por defecto) — Fijo a 6rem desde la parte inferior, centrado horizontalmente.
|
|
83
|
+
* - `'top'` — Fijo a 6rem desde la parte superior, centrado horizontalmente.
|
|
84
84
|
*
|
|
85
85
|
* @default 'bottom'
|
|
86
86
|
*/
|
|
@@ -88,21 +88,21 @@ export class MoniSnackbar extends MoniElement {
|
|
|
88
88
|
placement: 'bottom' | 'top' = 'bottom';
|
|
89
89
|
|
|
90
90
|
/**
|
|
91
|
-
*
|
|
91
|
+
* Cuando es `true`, el snackbar es visible.
|
|
92
92
|
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
93
|
+
* Alterne este atributo para mostrar/ocultar el snackbar. La transición CSS
|
|
94
|
+
* maneja la animación de desvanecimiento/deslizamiento hacia arriba (fade-in/slide-up) automáticamente.
|
|
95
|
+
* Los consumidores son responsables de implementar el temporizador de cierre automático.
|
|
96
96
|
*
|
|
97
97
|
* @default false
|
|
98
98
|
*/
|
|
99
99
|
@property({ type: Boolean, reflect: true }) active = false;
|
|
100
100
|
|
|
101
101
|
/**
|
|
102
|
-
*
|
|
102
|
+
* Número máximo de líneas del texto del mensaje antes de que sea limitado (clamped).
|
|
103
103
|
*
|
|
104
|
-
*
|
|
105
|
-
*
|
|
104
|
+
* Utiliza `-webkit-line-clamp` con `display: -webkit-box` para truncamiento multilínea
|
|
105
|
+
* compatible en varios navegadores. La especificación M3 recomienda un máximo de 2 líneas.
|
|
106
106
|
*
|
|
107
107
|
* @default 2
|
|
108
108
|
*/
|
|
@@ -194,6 +194,16 @@ export class MoniSnackbar extends MoniElement {
|
|
|
194
194
|
`
|
|
195
195
|
];
|
|
196
196
|
|
|
197
|
+
/**
|
|
198
|
+
* Renderiza el snackbar con su mensaje y el botón de acción opcional.
|
|
199
|
+
*
|
|
200
|
+
* El contenedor del snackbar utiliza `aria-live="polite"` para que los lectores
|
|
201
|
+
* de pantalla anuncien el mensaje sin interrumpir el flujo de lectura actual del usuario.
|
|
202
|
+
* Cuando se establece `action`, se renderiza un `<span>` como botón de acción según
|
|
203
|
+
* la especificación del Snackbar de M3.
|
|
204
|
+
* El atributo `placement` se asigna a una clase CSS que controla `inset-block-end`
|
|
205
|
+
* (snackbar inferior) vs `inset-block-start` (snackbar superior).
|
|
206
|
+
*/
|
|
197
207
|
override render() {
|
|
198
208
|
return html`<div
|
|
199
209
|
class="snackbar ${this.placement}"
|
|
@@ -10,48 +10,64 @@ import { customElement, property, queryAssignedElements } from 'lit/decorators.j
|
|
|
10
10
|
import { MoniElement, sharedStyles } from './_base/index.js';
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
-
* Material Design 3 Split Button
|
|
13
|
+
* Componente Material Design 3 Split Button (Botón dividido).
|
|
14
14
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
15
|
+
* Un botón dividido combina un botón de acción principal con un botón secundario desplegable.
|
|
16
|
+
* Los dos botones se asientan a ras uno del otro, típicamente compartiendo
|
|
17
|
+
* un color de fondo y elevación, pero separados por un borde distinto.
|
|
18
18
|
*
|
|
19
|
-
* **
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
19
|
+
* **Arquitectura visual:**
|
|
20
|
+
* El componente actúa como un contenedor de diseño (`display: inline-flex`) que
|
|
21
|
+
* agrupa dos botones estándar. Anula (overrides) los márgenes del botón posterior (trailing)
|
|
22
|
+
* para crear el aspecto "conectado" (similar a los grupos de botones conectados).
|
|
23
23
|
*
|
|
24
|
-
* **
|
|
25
|
-
*
|
|
26
|
-
* - `slot="leading-button"` —
|
|
27
|
-
* - `slot="trailing-button"` —
|
|
24
|
+
* **Uso:**
|
|
25
|
+
* Los consumidores deben proporcionar exactamente dos botones a través de los slots con nombre:
|
|
26
|
+
* - `slot="leading-button"` — La acción principal (usualmente texto o texto+icono).
|
|
27
|
+
* - `slot="trailing-button"` — La acción secundaria (usualmente solo un icono desplegable).
|
|
28
28
|
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
29
|
+
* Ambos botones deben ser elementos `<moni-button>` o `<moni-icon-button>` estándar
|
|
30
|
+
* configurados con variantes coincidentes para una apariencia cohesiva.
|
|
31
31
|
*
|
|
32
32
|
* @example
|
|
33
33
|
* ```html
|
|
34
34
|
* <moni-split-button variant="filled">
|
|
35
|
-
* <moni-button slot="leading-button" icon="send">
|
|
35
|
+
* <moni-button slot="leading-button" icon="send">Enviar</moni-button>
|
|
36
36
|
* <moni-button slot="trailing-button" icon="arrow_drop_down" id="schedule-trigger"></moni-button>
|
|
37
37
|
* </moni-split-button>
|
|
38
38
|
*
|
|
39
39
|
* <moni-menu id="schedule-menu" placement="bottom">
|
|
40
|
-
* <moni-menu-item>
|
|
40
|
+
* <moni-menu-item>Programar envío...</moni-menu-item>
|
|
41
41
|
* </moni-menu>
|
|
42
42
|
* ```
|
|
43
43
|
*
|
|
44
|
-
* @slot leading-button -
|
|
45
|
-
* @slot trailing-button -
|
|
44
|
+
* @slot leading-button - El botón de acción principal a la izquierda.
|
|
45
|
+
* @slot trailing-button - La acción secundaria (disparador desplegable) a la derecha.
|
|
46
46
|
*/
|
|
47
47
|
@customElement('moni-split-button')
|
|
48
48
|
export class MoniSplitButton extends MoniElement {
|
|
49
|
+
/**
|
|
50
|
+
* Variante visual del contenedor del botón dividido.
|
|
51
|
+
* Pasa las sugerencias de estilo apropiadas a sus hijos.
|
|
52
|
+
* @type {'filled' | 'tonal' | 'outlined' | 'elevated'}
|
|
53
|
+
* @default 'filled'
|
|
54
|
+
*/
|
|
49
55
|
@property({ reflect: true })
|
|
50
56
|
variant: 'filled' | 'tonal' | 'outlined' | 'elevated' = 'filled';
|
|
51
57
|
|
|
58
|
+
/**
|
|
59
|
+
* Tamaño global aplicado a ambos botones en los slots.
|
|
60
|
+
* @type {'xsmall' | 'small' | 'medium' | 'large' | 'xlarge' | 'extra'}
|
|
61
|
+
* @default 'medium'
|
|
62
|
+
*/
|
|
52
63
|
@property({ reflect: true })
|
|
53
64
|
size: 'xsmall' | 'small' | 'medium' | 'large' | 'xlarge' | 'extra' = 'medium';
|
|
54
65
|
|
|
66
|
+
/**
|
|
67
|
+
* El espacio (gap) CSS entre los botones líder y posterior.
|
|
68
|
+
* Normalmente 1px o 0 según la especificación M3.
|
|
69
|
+
* @type {string}
|
|
70
|
+
*/
|
|
55
71
|
@property()
|
|
56
72
|
gap = '';
|
|
57
73
|
|
|
@@ -83,6 +99,11 @@ export class MoniSplitButton extends MoniElement {
|
|
|
83
99
|
`
|
|
84
100
|
];
|
|
85
101
|
|
|
102
|
+
/**
|
|
103
|
+
* Hook del ciclo de vida reactivo (Lit).
|
|
104
|
+
* Responde a cualquier cambio en `variant`, `size` o `gap`
|
|
105
|
+
* forzando una actualización hacia todos los botones anidados.
|
|
106
|
+
*/
|
|
86
107
|
protected override updated(changedProperties: Map<string | number | symbol, unknown>) {
|
|
87
108
|
super.updated(changedProperties);
|
|
88
109
|
if (changedProperties.has('variant') || changedProperties.has('size') || changedProperties.has('gap')) {
|
|
@@ -90,6 +111,11 @@ export class MoniSplitButton extends MoniElement {
|
|
|
90
111
|
}
|
|
91
112
|
}
|
|
92
113
|
|
|
114
|
+
/**
|
|
115
|
+
* Manejador del slot change.
|
|
116
|
+
* Cuando los botones líder o cola se inyectan en el DOM,
|
|
117
|
+
* propaga las configuraciones físicas.
|
|
118
|
+
*/
|
|
93
119
|
private handleSlotChange() {
|
|
94
120
|
this.updateChildren();
|
|
95
121
|
}
|
|
@@ -105,6 +131,12 @@ export class MoniSplitButton extends MoniElement {
|
|
|
105
131
|
return gap;
|
|
106
132
|
}
|
|
107
133
|
|
|
134
|
+
/**
|
|
135
|
+
* Sincronizador de Propiedades.
|
|
136
|
+
* Distingue explícitamente entre el botón primario (leading) y el secundario (trailing)
|
|
137
|
+
* que usualmente alberga un ícono de dropdown. A cada uno se le inyecta un `shape`
|
|
138
|
+
* distinto (`left-round-flat` vs `right-round-flat`) para que juntos formen una cápsula pill uniforme.
|
|
139
|
+
*/
|
|
108
140
|
private updateChildren() {
|
|
109
141
|
const leading = this.leadingElements.find(
|
|
110
142
|
(el) => el.tagName.toLowerCase() === 'moni-button' || el.tagName.toLowerCase() === 'moni-icon-button'
|
|
@@ -128,6 +160,19 @@ export class MoniSplitButton extends MoniElement {
|
|
|
128
160
|
}
|
|
129
161
|
}
|
|
130
162
|
|
|
163
|
+
/**
|
|
164
|
+
* Renderiza el botón dividido como un control compuesto: botón de acción principal + disparador desplegable.
|
|
165
|
+
*
|
|
166
|
+
* **Diseño de dos zonas:**
|
|
167
|
+
* - Botón principal (zona líder) — la acción principal; lleva el `icon` y
|
|
168
|
+
* la etiqueta del slot por defecto. Al hacer clic se dispara el evento principal `click`.
|
|
169
|
+
* - Disparador desplegable (zona posterior) — un botón de icono secundario (icono `expand_more`)
|
|
170
|
+
* que abre el menú desplegable. Ambas zonas comparten el mismo `variant` y `size`.
|
|
171
|
+
*
|
|
172
|
+
* **Borde compartido:**
|
|
173
|
+
* Los dos botones usan los atributos de forma (shape) `left-round` / `right-round` para
|
|
174
|
+
* crear una sola píldora (pill) conectada con un borde interior compartido.
|
|
175
|
+
*/
|
|
131
176
|
override render() {
|
|
132
177
|
const resolvedGap = this.getGapValue(this.gap);
|
|
133
178
|
const inlineStyles = resolvedGap
|
|
@@ -29,12 +29,12 @@ describe('moni-step vertical connectors (P2.2)', () => {
|
|
|
29
29
|
stepper.remove();
|
|
30
30
|
});
|
|
31
31
|
|
|
32
|
-
it('vertical
|
|
32
|
+
it('la orientación vertical se propaga al host', async () => {
|
|
33
33
|
await stepper.updateComplete;
|
|
34
34
|
expect(stepper.getAttribute('orientation')).toBe('vertical');
|
|
35
35
|
});
|
|
36
36
|
|
|
37
|
-
it('
|
|
37
|
+
it('tres pasos verticales se renderizan en orden de documento', async () => {
|
|
38
38
|
await stepper.updateComplete;
|
|
39
39
|
await stepA.updateComplete;
|
|
40
40
|
const steps = Array.from(stepper.querySelectorAll('moni-step'));
|
|
@@ -44,13 +44,13 @@ describe('moni-step vertical connectors (P2.2)', () => {
|
|
|
44
44
|
expect(steps[2]).toBe(stepC);
|
|
45
45
|
});
|
|
46
46
|
|
|
47
|
-
it('
|
|
47
|
+
it('el último paso no tiene conector (solo :not(:last-child) tienen ::after)', async () => {
|
|
48
48
|
await stepper.updateComplete;
|
|
49
49
|
await stepC.updateComplete;
|
|
50
|
-
//
|
|
51
|
-
//
|
|
52
|
-
// pseudo-
|
|
53
|
-
//
|
|
50
|
+
// El selector :host(:not(:last-child))::after del host solo se aplica
|
|
51
|
+
// a los pasos que no son el último. El último paso no debería tener un
|
|
52
|
+
// pseudo-elemento conector visible. No podemos leer fácilmente ::after en jsdom
|
|
53
|
+
// pero verificamos que el último paso exista y se renderice.
|
|
54
54
|
const lastDot = stepC.shadowRoot?.querySelector('.dot');
|
|
55
55
|
expect(lastDot).toBeTruthy();
|
|
56
56
|
});
|
|
@@ -11,42 +11,42 @@ import { MoniElement, sharedStyles } from './_base/index.js';
|
|
|
11
11
|
import './moni-icon.js';
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
|
-
* Material Design 3 Step
|
|
14
|
+
* Componente Material Design 3 Step (Paso).
|
|
15
15
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
16
|
+
* Un paso individual dentro de un `<moni-stepper>`. Los pasos muestran el progreso a través
|
|
17
|
+
* de una secuencia de operaciones lógicas y numeradas.
|
|
18
18
|
*
|
|
19
|
-
* **
|
|
19
|
+
* **Referencia a la especificación M3:** `m3-docs/components/progress-indicators/specs.md` (Patrón Stepper)
|
|
20
20
|
*
|
|
21
|
-
* **
|
|
22
|
-
*
|
|
23
|
-
* (
|
|
24
|
-
*
|
|
25
|
-
*
|
|
21
|
+
* **Anatomía y aspecto visual:**
|
|
22
|
+
* Un paso renderiza un indicador circular que contiene ya sea su número de secuencia
|
|
23
|
+
* (inyectado automáticamente por el stepper padre) o un icono personalizado. Debajo o
|
|
24
|
+
* al lado del indicador (dependiendo de la `orientation` del padre), renderiza
|
|
25
|
+
* el `title` (título) y un `description` (descripción) opcional.
|
|
26
26
|
*
|
|
27
|
-
* **
|
|
28
|
-
*
|
|
29
|
-
* `active
|
|
30
|
-
* - **Active:**
|
|
31
|
-
* - **Completed:**
|
|
32
|
-
*
|
|
27
|
+
* **Gestión del estado:**
|
|
28
|
+
* El `<moni-stepper>` padre calcula e inyecta automáticamente las propiedades `index`,
|
|
29
|
+
* `active` y `completed` basándose en su estado actual.
|
|
30
|
+
* - **Activo (Active):** Resaltado con el color primario, indicando el paso actual.
|
|
31
|
+
* - **Completado (Completed):** Se muestra con un fondo primario sólido y un icono de
|
|
32
|
+
* marca de verificación (el estado `completed` anula el índice numérico).
|
|
33
33
|
*
|
|
34
34
|
* @example
|
|
35
35
|
* ```html
|
|
36
|
-
* <!--
|
|
36
|
+
* <!-- Típicamente usado dentro de un stepper -->
|
|
37
37
|
* <moni-stepper current="1">
|
|
38
|
-
* <moni-step title="
|
|
39
|
-
* <moni-step title="
|
|
40
|
-
* <moni-step title="
|
|
38
|
+
* <moni-step title="Envío" description="Ingresar dirección"></moni-step>
|
|
39
|
+
* <moni-step title="Pago" description="Detalles de tarjeta de crédito"></moni-step>
|
|
40
|
+
* <moni-step title="Revisión" description="Confirmar pedido"></moni-step>
|
|
41
41
|
* </moni-stepper>
|
|
42
42
|
*
|
|
43
|
-
* <!--
|
|
44
|
-
* <moni-step title="
|
|
43
|
+
* <!-- Anulando el icono -->
|
|
44
|
+
* <moni-step title="Hecho" icon="celebration"></moni-step>
|
|
45
45
|
* ```
|
|
46
46
|
*
|
|
47
|
-
* @csspart step-indicator -
|
|
48
|
-
* @csspart title -
|
|
49
|
-
* @csspart description -
|
|
47
|
+
* @csspart step-indicator - La insignia circular que contiene el número/icono.
|
|
48
|
+
* @csspart title - El texto principal del título.
|
|
49
|
+
* @csspart description - El texto secundario de la descripción.
|
|
50
50
|
*/
|
|
51
51
|
@customElement('moni-step')
|
|
52
52
|
export class MoniStep extends MoniElement {
|
|
@@ -91,11 +91,11 @@ export class MoniStep extends MoniElement {
|
|
|
91
91
|
min-block-size: 4rem;
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
/*
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
94
|
+
/* Conector vertical. Geometría: el punto (dot) ocupa y=0 a y=2rem en
|
|
95
|
+
la parte superior del paso (el host es flex de columna con min-block-size 4rem).
|
|
96
|
+
El conector va desde la parte INFERIOR del punto actual (y=2rem) hasta
|
|
97
|
+
la parte INFERIOR del paso actual (y=100%). Esta fórmula se mantiene
|
|
98
|
+
calibrada independientemente de la altura del paso. */
|
|
99
99
|
:host-context(moni-stepper[orientation='vertical']):host(:not(:last-child))::after {
|
|
100
100
|
position: absolute;
|
|
101
101
|
inset-inline-start: calc(1rem - 0.03125rem);
|
|
@@ -160,6 +160,18 @@ export class MoniStep extends MoniElement {
|
|
|
160
160
|
`
|
|
161
161
|
];
|
|
162
162
|
|
|
163
|
+
/**
|
|
164
|
+
* Renderiza el indicador del paso y la etiqueta (el conector se hace vía CSS ::after).
|
|
165
|
+
*
|
|
166
|
+
* **Indicador de paso (Step indicator):**
|
|
167
|
+
* - `completed=true` — muestra un icono de marca de verificación.
|
|
168
|
+
* - `active=true` — muestra el número de paso en un contenedor resaltado (vía CSS).
|
|
169
|
+
* - De lo contrario — muestra el número de paso en un estilo tenue.
|
|
170
|
+
*
|
|
171
|
+
* **Contenido del Slot:**
|
|
172
|
+
* El slot por defecto permite a los consumidores proyectar contenido personalizado
|
|
173
|
+
* dentro del cuerpo del paso.
|
|
174
|
+
*/
|
|
163
175
|
override render() {
|
|
164
176
|
const dot = this.completed
|
|
165
177
|
? html`<moni-icon name="check"></moni-icon>`
|
|
@@ -16,7 +16,7 @@ describe('moni-stepper / moni-step', () => {
|
|
|
16
16
|
el.remove();
|
|
17
17
|
});
|
|
18
18
|
|
|
19
|
-
it('
|
|
19
|
+
it('renderiza un <ol> con un slot', async () => {
|
|
20
20
|
await el.updateComplete;
|
|
21
21
|
const ol = el.shadowRoot?.querySelector('ol');
|
|
22
22
|
const slot = el.shadowRoot?.querySelector('slot');
|
|
@@ -24,19 +24,19 @@ describe('moni-stepper / moni-step', () => {
|
|
|
24
24
|
expect(slot).toBeTruthy();
|
|
25
25
|
});
|
|
26
26
|
|
|
27
|
-
it('
|
|
27
|
+
it('refleja el atributo orientation', async () => {
|
|
28
28
|
el.orientation = 'vertical';
|
|
29
29
|
await el.updateComplete;
|
|
30
30
|
expect(el.getAttribute('orientation')).toBe('vertical');
|
|
31
31
|
});
|
|
32
32
|
|
|
33
|
-
it('
|
|
33
|
+
it('refleja el atributo current como un número', async () => {
|
|
34
34
|
el.current = 2;
|
|
35
35
|
await el.updateComplete;
|
|
36
36
|
expect(el.getAttribute('current')).toBe('2');
|
|
37
37
|
});
|
|
38
38
|
|
|
39
|
-
it('
|
|
39
|
+
it('propaga current a los hijos: establece active en el paso coincidente', async () => {
|
|
40
40
|
const step1 = document.createElement('moni-step') as MoniStep;
|
|
41
41
|
step1.title = 'One';
|
|
42
42
|
const step2 = document.createElement('moni-step') as MoniStep;
|
|
@@ -61,7 +61,7 @@ describe('moni-stepper / moni-step', () => {
|
|
|
61
61
|
expect(step3.completed).toBe(false);
|
|
62
62
|
});
|
|
63
63
|
|
|
64
|
-
it('
|
|
64
|
+
it('establece el índice en cada hijo según su posición', async () => {
|
|
65
65
|
const s1 = document.createElement('moni-step') as MoniStep;
|
|
66
66
|
const s2 = document.createElement('moni-step') as MoniStep;
|
|
67
67
|
const s3 = document.createElement('moni-step') as MoniStep;
|
|
@@ -77,7 +77,7 @@ describe('moni-stepper / moni-step', () => {
|
|
|
77
77
|
expect(s3.index).toBe(2);
|
|
78
78
|
});
|
|
79
79
|
|
|
80
|
-
it('
|
|
80
|
+
it('marca todos los pasos anteriores como completados (completed)', async () => {
|
|
81
81
|
const s1 = document.createElement('moni-step') as MoniStep;
|
|
82
82
|
const s2 = document.createElement('moni-step') as MoniStep;
|
|
83
83
|
const s3 = document.createElement('moni-step') as MoniStep;
|
|
@@ -103,7 +103,7 @@ describe('moni-stepper / moni-step', () => {
|
|
|
103
103
|
expect(s4.active).toBe(false);
|
|
104
104
|
});
|
|
105
105
|
|
|
106
|
-
it('
|
|
106
|
+
it('se resincroniza cuando se agrega un paso dinámicamente (slotchange)', async () => {
|
|
107
107
|
el.current = 0;
|
|
108
108
|
await el.updateComplete;
|
|
109
109
|
const s1 = document.createElement('moni-step') as MoniStep;
|