@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,7 +14,7 @@ describe('moni-side-sheet', () => {
|
|
|
14
14
|
el.remove();
|
|
15
15
|
});
|
|
16
16
|
|
|
17
|
-
it('
|
|
17
|
+
it('se inicializa con valores por defecto', async () => {
|
|
18
18
|
await el.updateComplete;
|
|
19
19
|
expect(el.open).toBe(false);
|
|
20
20
|
expect(el.modal).toBe(false);
|
|
@@ -25,7 +25,7 @@ describe('moni-side-sheet', () => {
|
|
|
25
25
|
expect(el.showBack).toBe(false);
|
|
26
26
|
});
|
|
27
27
|
|
|
28
|
-
it('
|
|
28
|
+
it('refleja el estado open al dialog subyacente', async () => {
|
|
29
29
|
await el.updateComplete;
|
|
30
30
|
const dialog = el.shadowRoot?.querySelector('dialog') as HTMLDialogElement;
|
|
31
31
|
expect(dialog.open).toBe(false);
|
|
@@ -35,7 +35,7 @@ describe('moni-side-sheet', () => {
|
|
|
35
35
|
expect(dialog.open).toBe(true);
|
|
36
36
|
});
|
|
37
37
|
|
|
38
|
-
it('
|
|
38
|
+
it('renderiza el título y maneja el clic de cerrar', async () => {
|
|
39
39
|
el.title = 'Configuración';
|
|
40
40
|
el.open = true;
|
|
41
41
|
await el.updateComplete;
|
|
@@ -57,7 +57,7 @@ describe('moni-side-sheet', () => {
|
|
|
57
57
|
expect(eventFired).toBe(true);
|
|
58
58
|
});
|
|
59
59
|
|
|
60
|
-
it('
|
|
60
|
+
it('dispara el evento back cuando se hace clic en el botón de volver', async () => {
|
|
61
61
|
el.showBack = true;
|
|
62
62
|
await el.updateComplete;
|
|
63
63
|
|
|
@@ -73,7 +73,7 @@ describe('moni-side-sheet', () => {
|
|
|
73
73
|
expect(backFired).toBe(true);
|
|
74
74
|
});
|
|
75
75
|
|
|
76
|
-
it('
|
|
76
|
+
it('aplica la clase correcta para noBorder', async () => {
|
|
77
77
|
const dialog = el.shadowRoot?.querySelector('dialog');
|
|
78
78
|
expect(dialog?.classList.contains('no-border')).toBe(false);
|
|
79
79
|
|
|
@@ -82,7 +82,7 @@ describe('moni-side-sheet', () => {
|
|
|
82
82
|
expect(dialog?.classList.contains('no-border')).toBe(true);
|
|
83
83
|
});
|
|
84
84
|
|
|
85
|
-
it('
|
|
85
|
+
it('renderiza el tirador (handle) y soporta el cierre por arrastre cuando withHandle es true', async () => {
|
|
86
86
|
el.withHandle = true;
|
|
87
87
|
el.open = true;
|
|
88
88
|
await el.updateComplete;
|
|
@@ -113,7 +113,7 @@ describe('moni-side-sheet', () => {
|
|
|
113
113
|
closeFired = true;
|
|
114
114
|
});
|
|
115
115
|
|
|
116
|
-
//
|
|
116
|
+
// Activar el arrastre del puntero hacia la derecha en una hoja alineada a la derecha
|
|
117
117
|
handle.dispatchEvent(new PointerEvent('pointerdown', { bubbles: true, clientX: 300, pointerId: 1 }));
|
|
118
118
|
dialog.dispatchEvent(new PointerEvent('pointermove', { bubbles: true, clientX: 550, pointerId: 1 })); // 250px right (greater than 400 * 0.4 = 160px)
|
|
119
119
|
handle.dispatchEvent(new PointerEvent('pointerup', { bubbles: true, clientX: 550, pointerId: 1 }));
|
|
@@ -12,55 +12,55 @@ import './moni-icon.js';
|
|
|
12
12
|
import './moni-button.js';
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
* Material Design 3 Side Sheet
|
|
15
|
+
* Componente Material Design 3 Side Sheet (Hoja o panel lateral).
|
|
16
16
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* (
|
|
17
|
+
* Los paneles laterales muestran contenido complementario que está anclado al borde
|
|
18
|
+
* izquierdo o derecho de la pantalla. Pueden ser estándar (en línea con el contenido)
|
|
19
|
+
* o modales (superpuestos al contenido con un fondo/scrim oscurecido).
|
|
20
20
|
*
|
|
21
|
-
* **
|
|
21
|
+
* **Referencia a la especificación M3:** `m3-docs/components/side-sheets/specs.md`
|
|
22
22
|
*
|
|
23
|
-
* **Dialog behavior:**
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* -
|
|
27
|
-
* backdrop
|
|
28
|
-
* -
|
|
29
|
-
*
|
|
23
|
+
* **Comportamiento del cuadro de diálogo (Dialog behavior):**
|
|
24
|
+
* Internamente, este componente utiliza el elemento HTML nativo `<dialog>` para una
|
|
25
|
+
* accesibilidad robusta, captura de foco y renderizado en la capa superior (top-layer).
|
|
26
|
+
* - Cuando `modal=true`, el panel usa `dialog.showModal()`, renderizando un fondo
|
|
27
|
+
* (scrim backdrop) y capturando el foco. Al presionar `Escape` se cierra.
|
|
28
|
+
* - Cuando `modal=false`, el panel usa `dialog.show()` y permanece interactivo
|
|
29
|
+
* junto al contenido de la página principal.
|
|
30
30
|
*
|
|
31
|
-
* **
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
31
|
+
* **Arrastrar y redimensionar (Característica Moni):**
|
|
32
|
+
* Al configurar el atributo `with-handle`, se agrega un controlador de arrastre en el borde
|
|
33
|
+
* interior del panel. Los usuarios pueden hacer clic y arrastrar este controlador para
|
|
34
|
+
* redimensionar el ancho del panel hasta el límite `max-width`. Si el usuario arrastra
|
|
35
|
+
* el panel hacia el borde de la pantalla rápidamente o más allá de cierto umbral, se cierra automáticamente.
|
|
36
36
|
*
|
|
37
|
-
* **
|
|
38
|
-
*
|
|
39
|
-
*
|
|
37
|
+
* **Animaciones:**
|
|
38
|
+
* Los paneles laterales se deslizan desde el `side` (lado) especificado (`left` o `right`).
|
|
39
|
+
* Las animaciones de apertura y cierre se manejan a través de transiciones CSS vinculadas a la propiedad `open`.
|
|
40
40
|
*
|
|
41
|
-
* @fires close -
|
|
42
|
-
*
|
|
43
|
-
*
|
|
41
|
+
* @fires close - Se dispara cuando el panel lateral está completamente cerrado (después de
|
|
42
|
+
* que terminan las animaciones), ya sea a través del botón de cierre, clic en el fondo (scrim),
|
|
43
|
+
* arrastrar para cerrar o la tecla `Escape`.
|
|
44
44
|
*
|
|
45
45
|
* @example
|
|
46
46
|
* ```html
|
|
47
|
-
* <!--
|
|
48
|
-
* <moni-side-sheet id="details-sheet" modal title="
|
|
49
|
-
* <p>
|
|
47
|
+
* <!-- Panel lateral modal a la derecha -->
|
|
48
|
+
* <moni-side-sheet id="details-sheet" modal title="Detalles del artículo">
|
|
49
|
+
* <p>Aquí hay más información sobre el artículo seleccionado.</p>
|
|
50
50
|
* <div slot="footer">
|
|
51
|
-
* <moni-button>
|
|
51
|
+
* <moni-button>Guardar</moni-button>
|
|
52
52
|
* </div>
|
|
53
53
|
* </moni-side-sheet>
|
|
54
54
|
*
|
|
55
|
-
* <!--
|
|
55
|
+
* <!-- Panel lateral a la izquierda, desvinculado (detached) y redimensionable -->
|
|
56
56
|
* <moni-side-sheet side="left" detached with-handle max-width="50vw">
|
|
57
|
-
* <p>
|
|
57
|
+
* <p>Opciones de navegación</p>
|
|
58
58
|
* </moni-side-sheet>
|
|
59
59
|
* ```
|
|
60
60
|
*
|
|
61
|
-
* @slot default -
|
|
62
|
-
* @slot header -
|
|
63
|
-
* @slot footer -
|
|
61
|
+
* @slot default - Contenido del cuerpo principal.
|
|
62
|
+
* @slot header - Contenido de encabezado personalizado (anula `title`, los botones de cerrar/volver permanecen).
|
|
63
|
+
* @slot footer - Área de acción anclada en la parte inferior.
|
|
64
64
|
*/
|
|
65
65
|
@customElement('moni-side-sheet')
|
|
66
66
|
export class MoniSideSheet extends MoniElement {
|
|
@@ -99,6 +99,14 @@ export class MoniSideSheet extends MoniElement {
|
|
|
99
99
|
return 600;
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
+
/**
|
|
103
|
+
* Hook del ciclo de vida reactivo (Lit).
|
|
104
|
+
* Coordina la transición del elemento `<dialog>` nativo.
|
|
105
|
+
* Utiliza `showModal()` para Side Sheets modales (con backdrop) y `show()`
|
|
106
|
+
* para Side Sheets estándar. Administra manualmente la clase `.opened` y escucha
|
|
107
|
+
* eventos `transitionend` para cerrar limpiamente el `<dialog>` sólo cuando
|
|
108
|
+
* las animaciones CSS terminan.
|
|
109
|
+
*/
|
|
102
110
|
override updated(changedProperties: PropertyValues) {
|
|
103
111
|
super.updated(changedProperties);
|
|
104
112
|
|
|
@@ -156,6 +164,12 @@ export class MoniSideSheet extends MoniElement {
|
|
|
156
164
|
}
|
|
157
165
|
}
|
|
158
166
|
|
|
167
|
+
/**
|
|
168
|
+
* Inicia la interacción de arrastre (Drag) del Side Sheet.
|
|
169
|
+
* Verifica si el usuario agarró el componente desde el "handle" o la cabecera.
|
|
170
|
+
* Captura el ancho actual para determinar si el usuario pretende expandir o contraer
|
|
171
|
+
* el panel lateral mediante gestos.
|
|
172
|
+
*/
|
|
159
173
|
private _onPointerDown(e: PointerEvent) {
|
|
160
174
|
if (!this.withHandle) return;
|
|
161
175
|
const target = e.target as HTMLElement;
|
|
@@ -175,6 +189,13 @@ export class MoniSideSheet extends MoniElement {
|
|
|
175
189
|
this._dialog.classList.add('dragging');
|
|
176
190
|
}
|
|
177
191
|
|
|
192
|
+
/**
|
|
193
|
+
* Procesa el movimiento del arrastre y aplica transformaciones CSS inline
|
|
194
|
+
* imperativamente a 60FPS. Diferencia la lógica dependiendo de la posición
|
|
195
|
+
* de anclaje (izquierdo vs derecho) y del estado actual (expandido vs contraído).
|
|
196
|
+
* Introduce una "resistencia elástica" si el usuario intenta expandir el panel
|
|
197
|
+
* más allá de su ancho máximo permitido (`maxWidth`).
|
|
198
|
+
*/
|
|
178
199
|
private _onPointerMove(e: PointerEvent) {
|
|
179
200
|
if (!this._isDragging) return;
|
|
180
201
|
|
|
@@ -209,6 +230,15 @@ export class MoniSideSheet extends MoniElement {
|
|
|
209
230
|
}
|
|
210
231
|
}
|
|
211
232
|
|
|
233
|
+
/**
|
|
234
|
+
* Evalúa el resultado de la interacción de arrastre (Pointer Up).
|
|
235
|
+
*
|
|
236
|
+
* Basado en umbrales de distancia física (`threshold`) y el estado actual, decide:
|
|
237
|
+
* 1. Expandir el panel por completo (modo "expanded").
|
|
238
|
+
* 2. Contraer el panel de vuelta a su tamaño estándar.
|
|
239
|
+
* 3. Cerrar el Side Sheet totalmente y disparar el evento `close`.
|
|
240
|
+
* Utiliza transiciones CSS nativas en vez de animar por frame para la resolución final.
|
|
241
|
+
*/
|
|
212
242
|
private _onPointerUp(e: PointerEvent) {
|
|
213
243
|
if (!this._isDragging) return;
|
|
214
244
|
|
|
@@ -290,6 +320,11 @@ export class MoniSideSheet extends MoniElement {
|
|
|
290
320
|
}
|
|
291
321
|
}
|
|
292
322
|
|
|
323
|
+
/**
|
|
324
|
+
* Aborta limpiamente la interacción de arrastre (Pointer Cancel).
|
|
325
|
+
* Remueve estilos imperativos y clases de estado (`dragging`) si el navegador
|
|
326
|
+
* toma el control o la interacción se interrumpe prematuramente.
|
|
327
|
+
*/
|
|
293
328
|
private _onPointerCancel(e: PointerEvent) {
|
|
294
329
|
if (!this._isDragging) return;
|
|
295
330
|
const target = e.target as HTMLElement;
|
|
@@ -300,15 +335,30 @@ export class MoniSideSheet extends MoniElement {
|
|
|
300
335
|
this._dialog.style.width = '';
|
|
301
336
|
}
|
|
302
337
|
|
|
338
|
+
/**
|
|
339
|
+
* Manejador del botón "Cerrar" explícito (X).
|
|
340
|
+
* Modifica la propiedad `open` a false y despacha el evento de cierre.
|
|
341
|
+
*/
|
|
303
342
|
private _onCloseClick() {
|
|
304
343
|
this.open = false;
|
|
305
344
|
this.dispatchEvent(new CustomEvent('close', { bubbles: true, composed: true }));
|
|
306
345
|
}
|
|
307
346
|
|
|
347
|
+
/**
|
|
348
|
+
* Manejador del botón "Atrás".
|
|
349
|
+
* Emite un evento especializado `back` útil para Side Sheets de navegación anidada,
|
|
350
|
+
* permitiendo a los controladores padres reaccionar cambiando la vista interna.
|
|
351
|
+
*/
|
|
308
352
|
private _onBackClick() {
|
|
309
353
|
this.dispatchEvent(new CustomEvent('back', { bubbles: true, composed: true }));
|
|
310
354
|
}
|
|
311
355
|
|
|
356
|
+
/**
|
|
357
|
+
* Intercepta clics en el backdrop nativo del `<dialog>`.
|
|
358
|
+
* Si el componente es `modal`, hacer clic fuera del panel cierra la interfaz.
|
|
359
|
+
* Verifica `_justDragged` para evitar cerrar si el usuario hizo un click
|
|
360
|
+
* "accidental" derivado del final de un arrastre.
|
|
361
|
+
*/
|
|
312
362
|
private _onDialogClick(e: MouseEvent) {
|
|
313
363
|
if (this._justDragged) {
|
|
314
364
|
this._justDragged = false;
|
|
@@ -513,6 +563,18 @@ export class MoniSideSheet extends MoniElement {
|
|
|
513
563
|
`
|
|
514
564
|
];
|
|
515
565
|
|
|
566
|
+
/**
|
|
567
|
+
* Renderiza el panel lateral usando un elemento `<dialog>` nativo.
|
|
568
|
+
*
|
|
569
|
+
* **Manejo de estados:**
|
|
570
|
+
* Utiliza clases dinámicas para controlar el lado (`left`/`right`), el modo (`modal`/`standard`),
|
|
571
|
+
* y el estilo desvinculado (`detached`).
|
|
572
|
+
*
|
|
573
|
+
* **Atributo `[open]`:**
|
|
574
|
+
* La vinculación `?open=${this.open}` añade o remueve el atributo `open` nativo de HTML.
|
|
575
|
+
* Las transiciones visuales (slide-in/slide-out) son manejadas por el evento `transitionend`
|
|
576
|
+
* en el método `updated()` usando la clase `.opened`.
|
|
577
|
+
*/
|
|
516
578
|
override render() {
|
|
517
579
|
const classes = [
|
|
518
580
|
this.side,
|
|
@@ -14,13 +14,13 @@ describe('moni-slider (P3.4 — ticks)', () => {
|
|
|
14
14
|
el.remove();
|
|
15
15
|
});
|
|
16
16
|
|
|
17
|
-
it('
|
|
17
|
+
it('no renderiza un datalist por defecto', async () => {
|
|
18
18
|
await el.updateComplete;
|
|
19
19
|
const datalist = el.shadowRoot?.querySelector('datalist');
|
|
20
20
|
expect(datalist).toBeFalsy();
|
|
21
21
|
});
|
|
22
22
|
|
|
23
|
-
it('ticks=true
|
|
23
|
+
it('ticks=true renderiza un datalist con opciones min y max', async () => {
|
|
24
24
|
el.ticks = true;
|
|
25
25
|
await el.updateComplete;
|
|
26
26
|
const datalist = el.shadowRoot?.querySelector('datalist');
|
|
@@ -31,7 +31,7 @@ describe('moni-slider (P3.4 — ticks)', () => {
|
|
|
31
31
|
expect(options?.[1].getAttribute('value')).toBe('100');
|
|
32
32
|
});
|
|
33
33
|
|
|
34
|
-
it('tick-interval
|
|
34
|
+
it('tick-interval genera opciones de datalist cada N unidades', async () => {
|
|
35
35
|
el.min = '0';
|
|
36
36
|
el.max = '10';
|
|
37
37
|
el.tickInterval = 2;
|
|
@@ -43,7 +43,7 @@ describe('moni-slider (P3.4 — ticks)', () => {
|
|
|
43
43
|
expect(values).toEqual(['0', '2', '4', '6', '8', '10']);
|
|
44
44
|
});
|
|
45
45
|
|
|
46
|
-
it('tick-interval
|
|
46
|
+
it('tick-interval respeta un min distinto de cero', async () => {
|
|
47
47
|
el.min = '5';
|
|
48
48
|
el.max = '15';
|
|
49
49
|
el.tickInterval = 5;
|
|
@@ -54,7 +54,7 @@ describe('moni-slider (P3.4 — ticks)', () => {
|
|
|
54
54
|
expect(values).toEqual(['5', '10', '15']);
|
|
55
55
|
});
|
|
56
56
|
|
|
57
|
-
it('tick-interval
|
|
57
|
+
it('tick-interval tiene precedencia sobre el booleano ticks', async () => {
|
|
58
58
|
el.ticks = true;
|
|
59
59
|
el.min = '0';
|
|
60
60
|
el.max = '4';
|
|
@@ -66,13 +66,13 @@ describe('moni-slider (P3.4 — ticks)', () => {
|
|
|
66
66
|
expect(options.length).toBe(5);
|
|
67
67
|
});
|
|
68
68
|
|
|
69
|
-
it('
|
|
69
|
+
it('refleja el atributo tick-interval en el host', async () => {
|
|
70
70
|
el.tickInterval = 5;
|
|
71
71
|
await el.updateComplete;
|
|
72
72
|
expect(el.getAttribute('tick-interval')).toBe('5');
|
|
73
73
|
});
|
|
74
74
|
|
|
75
|
-
it('
|
|
75
|
+
it('refleja min y max en el host', async () => {
|
|
76
76
|
el.min = '10';
|
|
77
77
|
el.max = '20';
|
|
78
78
|
await el.updateComplete;
|
|
@@ -12,99 +12,190 @@ import { MoniElement, sharedStyles } from './_base/index.js';
|
|
|
12
12
|
import './moni-icon.js';
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
* Material Design 3 Slider
|
|
15
|
+
* Componente Material Design 3 Slider (Control deslizante).
|
|
16
16
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
17
|
+
* Los sliders permiten a los usuarios seleccionar un solo valor o un rango de valores
|
|
18
|
+
* desde una escala continua o discreta.
|
|
19
19
|
*
|
|
20
|
-
* **
|
|
20
|
+
* **Referencia a la especificación M3:** `m3-docs/components/sliders/specs.md`
|
|
21
21
|
*
|
|
22
|
-
* **Slider
|
|
23
|
-
* - **Continuous** (
|
|
24
|
-
*
|
|
25
|
-
* - **Discrete** —
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
* - **Range** (`range`
|
|
29
|
-
*
|
|
30
|
-
* - **Vertical** (`vertical`
|
|
22
|
+
* **Modos de Slider:**
|
|
23
|
+
* - **Continuo (Continuous)** (por defecto) — Arrastre suave entre `min` y `max`. Úsalo cuando
|
|
24
|
+
* no sea necesario que el usuario defina un valor exacto (ej. volumen).
|
|
25
|
+
* - **Discreto (Discrete)** — Configura `step` para ajustarse a intervalos discretos. Las marcas
|
|
26
|
+
* (tick marks) aparecen a través del elemento nativo `<datalist>` en Chrome/Edge. Firefox no
|
|
27
|
+
* renderiza marcas de datalist para inputs de tipo rango.
|
|
28
|
+
* - **Rango (Range)** (atributo `range`) — Dos controles (thumbs) que definen un valor mínimo y
|
|
29
|
+
* máximo dentro de la extensión del slider.
|
|
30
|
+
* - **Vertical** (atributo `vertical`) — Slider rotado 90°.
|
|
31
31
|
*
|
|
32
|
-
* **Value label tooltip:**
|
|
33
|
-
*
|
|
34
|
-
* (
|
|
32
|
+
* **Tooltip indicador de valor (Value label tooltip):**
|
|
33
|
+
* Cuando se configura `indicator`, el valor actual se muestra en un tooltip por encima
|
|
34
|
+
* (o por debajo, a través de `indicator-placement`) del control activo durante el foco/arrastre.
|
|
35
35
|
*
|
|
36
|
-
* **Tick marks:**
|
|
37
|
-
* - `ticks
|
|
38
|
-
* - `tick-interval
|
|
39
|
-
*
|
|
36
|
+
* **Marcas (Tick marks):**
|
|
37
|
+
* - Atributo `ticks`: agrega datalist con marcas solo en `min` y `max`.
|
|
38
|
+
* - Atributo `tick-interval`: genera opciones de datalist cada N unidades
|
|
39
|
+
* entre `min` y `max`, creando marcas visibles en esas posiciones.
|
|
40
40
|
*
|
|
41
|
-
* **
|
|
42
|
-
*
|
|
43
|
-
* tooltip
|
|
44
|
-
*
|
|
41
|
+
* **Manejo del estado interno:**
|
|
42
|
+
* Usa `@state()` para `_value` y `_valueHigh` de modo que el ancho de la pista de llenado y
|
|
43
|
+
* la posición del tooltip se actualicen de forma reactiva en cada evento `input` de arrastre sin
|
|
44
|
+
* esperar al evento `change`.
|
|
45
45
|
*
|
|
46
|
-
* @fires change -
|
|
47
|
-
*
|
|
48
|
-
* @fires input -
|
|
49
|
-
*
|
|
46
|
+
* @fires change - Burbujea y está compuesto. Se dispara cuando termina el arrastre y el
|
|
47
|
+
* valor se confirma. Lee `element.value` para el nuevo valor.
|
|
48
|
+
* @fires input - Se dispara en cada paso del arrastre. Lee `element.value` para el
|
|
49
|
+
* valor en vivo durante el arrastre.
|
|
50
50
|
*
|
|
51
51
|
* @example
|
|
52
52
|
* ```html
|
|
53
|
-
* <!--
|
|
53
|
+
* <!-- Slider continuo -->
|
|
54
54
|
* <moni-slider name="volume" min="0" max="100" value="60"></moni-slider>
|
|
55
55
|
*
|
|
56
|
-
* <!--
|
|
56
|
+
* <!-- Slider discreto con marcas cada 10 unidades -->
|
|
57
57
|
* <moni-slider step="10" tick-interval="10" indicator></moni-slider>
|
|
58
58
|
*
|
|
59
|
-
* <!--
|
|
59
|
+
* <!-- Slider de rango -->
|
|
60
60
|
* <moni-slider range min="0" max="100" value="20" value-high="80"></moni-slider>
|
|
61
61
|
* ```
|
|
62
62
|
*
|
|
63
|
-
* @csspart slider -
|
|
64
|
-
* @csspart track -
|
|
65
|
-
* @csspart fill -
|
|
66
|
-
* @csspart indicator -
|
|
63
|
+
* @csspart slider - El contenedor exterior del slider.
|
|
64
|
+
* @csspart track - El fondo de la pista.
|
|
65
|
+
* @csspart fill - La porción llena de la pista.
|
|
66
|
+
* @csspart indicator - El tooltip de la etiqueta de valor.
|
|
67
67
|
*/
|
|
68
68
|
@customElement('moni-slider')
|
|
69
69
|
export class MoniSlider extends MoniElement {
|
|
70
|
+
/**
|
|
71
|
+
* Nombre del input del slider, usado en el envío de formularios.
|
|
72
|
+
* @type {string}
|
|
73
|
+
*/
|
|
70
74
|
@property({ reflect: true }) name = '';
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Valor mínimo del slider.
|
|
78
|
+
* @type {string}
|
|
79
|
+
* @default '0'
|
|
80
|
+
*/
|
|
71
81
|
@property({ reflect: true }) min = '0';
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Valor máximo del slider.
|
|
85
|
+
* @type {string}
|
|
86
|
+
* @default '100'
|
|
87
|
+
*/
|
|
72
88
|
@property({ reflect: true }) max = '100';
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Granularidad del slider. Debe ser un número positivo.
|
|
92
|
+
* @type {string}
|
|
93
|
+
*/
|
|
73
94
|
@property({ reflect: true }) step = '';
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Anula (overrides) el intervalo predeterminado de las marcas cuando `ticks` es verdadero.
|
|
98
|
+
* @type {number | null}
|
|
99
|
+
*/
|
|
74
100
|
@property({ type: Number, reflect: true, attribute: 'tick-interval' })
|
|
75
101
|
tickInterval: number | null = null;
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Nombre del icono (Material Symbols) mostrado dentro del control (thumb) del slider.
|
|
105
|
+
* @type {string}
|
|
106
|
+
*/
|
|
76
107
|
@property({ reflect: true, attribute: 'inset-icon' }) insetIcon = '';
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Ubicación del tooltip indicador de valor.
|
|
111
|
+
* @type {'top' | 'bottom'}
|
|
112
|
+
* @default 'top'
|
|
113
|
+
*/
|
|
77
114
|
@property({ reflect: true, attribute: 'indicator-placement' })
|
|
78
115
|
indicatorPlacement: 'top' | 'bottom' = 'top';
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Grosor/tamaño de la pista y el control (thumb) del slider.
|
|
119
|
+
* @type {'tiny' | 'small' | 'medium' | 'large' | 'extra'}
|
|
120
|
+
* @default 'medium'
|
|
121
|
+
*/
|
|
79
122
|
@property({ reflect: true })
|
|
80
123
|
size: 'tiny' | 'small' | 'medium' | 'large' | 'extra' = 'medium';
|
|
81
124
|
|
|
82
|
-
|
|
125
|
+
/**
|
|
126
|
+
* Habilita el modo de rango (dos controles: `value` y `valueEnd`).
|
|
127
|
+
* @type {boolean}
|
|
128
|
+
*/
|
|
83
129
|
@property({ type: Boolean, reflect: true }) range = false;
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Deshabilita el slider.
|
|
133
|
+
* @type {boolean}
|
|
134
|
+
*/
|
|
84
135
|
@property({ type: Boolean, reflect: true }) disabled = false;
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Renderiza marcas (tick marks) a lo largo de la pista en cada intervalo de paso.
|
|
139
|
+
* @type {boolean}
|
|
140
|
+
*/
|
|
85
141
|
@property({ type: Boolean, reflect: true }) ticks = false;
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Muestra un indicador de tooltip mostrando el(los) valor(es) actual(es) mientras se arrastra.
|
|
145
|
+
* @type {boolean}
|
|
146
|
+
*/
|
|
86
147
|
@property({ type: Boolean, reflect: true }) indicator = false;
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Renderiza el slider de forma vertical en lugar de horizontal.
|
|
151
|
+
* @type {boolean}
|
|
152
|
+
*/
|
|
87
153
|
@property({ type: Boolean, reflect: true, attribute: 'vertical' }) isVertical = false;
|
|
88
154
|
|
|
89
|
-
/**
|
|
155
|
+
/** Estado reactivo interno — dispara actualizaciones de variables CSS en cada evento de input */
|
|
90
156
|
@state() private _value = '50';
|
|
91
157
|
@state() private _valueEnd = '75';
|
|
92
158
|
|
|
159
|
+
/**
|
|
160
|
+
* El valor primario actual del slider (o el límite inferior en modo de rango).
|
|
161
|
+
* @type {string}
|
|
162
|
+
*/
|
|
93
163
|
@property({ reflect: true })
|
|
94
164
|
get value() { return this._value; }
|
|
165
|
+
/**
|
|
166
|
+
* Intercepta asignaciones imperativas (`element.value = "X"`) para actualizar
|
|
167
|
+
* el estado interno de Lit, garantizando reactividad instantánea del DOM.
|
|
168
|
+
*/
|
|
95
169
|
set value(v: string) { this._value = v; }
|
|
96
170
|
|
|
171
|
+
/**
|
|
172
|
+
* El valor límite superior actual (solo usado cuando `range` es verdadero).
|
|
173
|
+
* @type {string}
|
|
174
|
+
*/
|
|
97
175
|
@property({ reflect: true, attribute: 'value-end' })
|
|
98
176
|
get valueEnd() { return this._valueEnd; }
|
|
177
|
+
/**
|
|
178
|
+
* Setter reactivo para el límite superior (usado exclusivamente en modo `range`).
|
|
179
|
+
*/
|
|
99
180
|
set valueEnd(v: string) { this._valueEnd = v; }
|
|
100
181
|
|
|
182
|
+
/**
|
|
183
|
+
* Calcula el porcentaje de llenado de la barra (0-100) basándose en el valor actual,
|
|
184
|
+
* el mínimo y el máximo. Se utiliza intensivamente para definir variables CSS (como `--_pct`).
|
|
185
|
+
*/
|
|
101
186
|
private _pct(v: string) {
|
|
102
187
|
const min = parseFloat(this.min) || 0;
|
|
103
188
|
const max = parseFloat(this.max) || 100;
|
|
104
189
|
const val = parseFloat(v) || 0;
|
|
190
|
+
// Math.max/min asegura que no desborde si por alguna razón val > max o val < min
|
|
105
191
|
return Math.max(0, Math.min(100, ((val - min) / (max - min)) * 100));
|
|
106
192
|
}
|
|
107
193
|
|
|
194
|
+
/**
|
|
195
|
+
* Maneja el evento nativo "input" de los inputs type="range" subyacentes.
|
|
196
|
+
* Se dispara contínuamente mientras el usuario arrastra el slider.
|
|
197
|
+
* Actualiza el estado reactivo inmediatamente para que la UI responda en tiempo real (60fps).
|
|
198
|
+
*/
|
|
108
199
|
private _onInput(e: Event, index: number) {
|
|
109
200
|
const target = e.target as HTMLInputElement;
|
|
110
201
|
if (index === 0) {
|
|
@@ -112,9 +203,14 @@ export class MoniSlider extends MoniElement {
|
|
|
112
203
|
} else {
|
|
113
204
|
this._valueEnd = target.value;
|
|
114
205
|
}
|
|
206
|
+
// Redisparamos el evento hacia afuera para que los frameworks (React/Vue/Angular) puedan atraparlo
|
|
115
207
|
this.dispatchEvent(new Event('input', { bubbles: true, composed: true }));
|
|
116
208
|
}
|
|
117
209
|
|
|
210
|
+
/**
|
|
211
|
+
* Maneja el evento nativo "change", que se dispara solo cuando el usuario SUELTA el slider
|
|
212
|
+
* (al terminar la interacción). Útil para peticiones HTTP pesadas o validaciones finales.
|
|
213
|
+
*/
|
|
118
214
|
private _onChange(e: Event, index: number) {
|
|
119
215
|
const target = e.target as HTMLInputElement;
|
|
120
216
|
if (index === 0) {
|
|
@@ -126,11 +222,11 @@ export class MoniSlider extends MoniElement {
|
|
|
126
222
|
}
|
|
127
223
|
|
|
128
224
|
/**
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
225
|
+
* Renderiza un elemento `<datalist>` con opciones de marcas. Cuando se establece
|
|
226
|
+
* `tick-interval`, genera opciones cada N unidades entre el mínimo y el máximo.
|
|
227
|
+
* De lo contrario, si se establece `ticks`, solo mínimo y máximo.
|
|
228
|
+
* Los navegadores que soportan marcas de datalist para inputs de rango (Chrome, Edge)
|
|
229
|
+
* renderizarán marcas visuales; Firefox las ignora.
|
|
134
230
|
*/
|
|
135
231
|
private _renderDatalist() {
|
|
136
232
|
if (this.tickInterval != null && this.tickInterval > 0) {
|
|
@@ -358,6 +454,33 @@ export class MoniSlider extends MoniElement {
|
|
|
358
454
|
`
|
|
359
455
|
];
|
|
360
456
|
|
|
457
|
+
/**
|
|
458
|
+
* Ensambla la estructura del Shadow DOM del slider.
|
|
459
|
+
*
|
|
460
|
+
* **Cálculo de la pista llena:**
|
|
461
|
+
* `pct` y `pctEnd` son valores porcentuales (0–100) derivados de
|
|
462
|
+
* `_pct(value)`. Se inyectan como propiedades CSS personalizadas `--_start` y `--_end`
|
|
463
|
+
* en el contenedor `.slider`. El pseudo-elemento CSS `::before`
|
|
464
|
+
* utiliza estos valores en un `clip-path: polygon(...)` para renderizar la parte
|
|
465
|
+
* no llena de la pista, mientras que el `<span>` renderiza la parte llena.
|
|
466
|
+
*
|
|
467
|
+
* **Modo Rango (`range=true`):**
|
|
468
|
+
* - Se renderizan dos elementos `<input type="range">` (uno para el límite inferior,
|
|
469
|
+
* otro para el límite superior).
|
|
470
|
+
* - El CSS los superpone absolutamente para que los controles (thumbs) compartan la misma línea de pista.
|
|
471
|
+
* - `--_start` equivale al porcentaje del control inferior; `--_end` equivale a `100 - pctEnd`.
|
|
472
|
+
*
|
|
473
|
+
* **Tooltip indicador:**
|
|
474
|
+
* Los elementos tooltip `.tooltip-1` / `.tooltip-2` están posicionados absolutamente
|
|
475
|
+
* utilizando `inset-inline-start: ${pct}%` de modo que siguen al control activo
|
|
476
|
+
* por encima (o por debajo) a medida que el usuario arrastra. La visibilidad se controla
|
|
477
|
+
* puramente a través de selectores CSS `:focus` — no se requiere JavaScript.
|
|
478
|
+
*
|
|
479
|
+
* **Datalist de marcas (Tick datalist):**
|
|
480
|
+
* `_renderDatalist()` emite un `<datalist id="ticks">` solo cuando `ticks` o
|
|
481
|
+
* `tick-interval` está establecido. Chrome/Edge renderizan marcas nativas en inputs de rango
|
|
482
|
+
* que referencian un datalist a través del atributo `list`; Firefox lo ignora.
|
|
483
|
+
*/
|
|
361
484
|
override render() {
|
|
362
485
|
const pct = this._pct(this._value);
|
|
363
486
|
const pctEnd = this._pct(this._valueEnd);
|