@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-color-field', () => {
|
|
|
14
14
|
el.remove();
|
|
15
15
|
});
|
|
16
16
|
|
|
17
|
-
it('
|
|
17
|
+
it('renderiza una muestra (swatch) y un input de texto', async () => {
|
|
18
18
|
await el.updateComplete;
|
|
19
19
|
const swatch = el.shadowRoot?.querySelector('.swatch');
|
|
20
20
|
const text = el.shadowRoot?.querySelector('input[type="text"]');
|
|
@@ -22,14 +22,14 @@ describe('moni-color-field', () => {
|
|
|
22
22
|
expect(text).toBeTruthy();
|
|
23
23
|
});
|
|
24
24
|
|
|
25
|
-
it('
|
|
25
|
+
it('agrega la clase active al input de texto cuando se establece el valor', async () => {
|
|
26
26
|
el.value = '#ff00aa';
|
|
27
27
|
await el.updateComplete;
|
|
28
28
|
const text = el.shadowRoot?.querySelector('input[type="text"]');
|
|
29
29
|
expect(text?.classList.contains('active')).toBe(true);
|
|
30
30
|
});
|
|
31
31
|
|
|
32
|
-
it('
|
|
32
|
+
it('reenvía el valor al input de texto', async () => {
|
|
33
33
|
el.value = '#123456';
|
|
34
34
|
await el.updateComplete;
|
|
35
35
|
const text = el.shadowRoot?.querySelector(
|
|
@@ -38,7 +38,7 @@ describe('moni-color-field', () => {
|
|
|
38
38
|
expect(text.value).toBe('#123456');
|
|
39
39
|
});
|
|
40
40
|
|
|
41
|
-
it('
|
|
41
|
+
it('mantiene el input de texto en readonly (para que la etiqueta pueda elevarse vía .active)', async () => {
|
|
42
42
|
await el.updateComplete;
|
|
43
43
|
const text = el.shadowRoot?.querySelector(
|
|
44
44
|
'input[type="text"]'
|
|
@@ -46,7 +46,7 @@ describe('moni-color-field', () => {
|
|
|
46
46
|
expect(text.hasAttribute('readonly')).toBe(true);
|
|
47
47
|
});
|
|
48
48
|
|
|
49
|
-
it('
|
|
49
|
+
it('renderiza el elemento label adyacente al input de texto para el selector de BeerCSS', async () => {
|
|
50
50
|
el.label = 'Pick a color';
|
|
51
51
|
await el.updateComplete;
|
|
52
52
|
const text = el.shadowRoot?.querySelector('input[type="text"]');
|
|
@@ -12,63 +12,123 @@ import { classMap } from 'lit/directives/class-map.js';
|
|
|
12
12
|
import { MoniElement, sharedStyles, fieldStyles } from './_base/index.js';
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
* Material Design 3 Color Field
|
|
15
|
+
* Componente Material Design 3 Color Field (Campo de Color).
|
|
16
16
|
*
|
|
17
|
-
*
|
|
18
|
-
* `<input type="color">`
|
|
19
|
-
*
|
|
17
|
+
* Un campo de texto especializado para la entrada de color que combina un
|
|
18
|
+
* `<input type="color">` nativo con una visualización de texto de solo lectura del
|
|
19
|
+
* valor hexadecimal seleccionado, envuelto en la carcasa estándar de campo M3.
|
|
20
20
|
*
|
|
21
|
-
* **
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
21
|
+
* **Arquitectura visual:**
|
|
22
|
+
* Extiende el patrón de estilo de campo usado por `<moni-text-field>`. El
|
|
23
|
+
* slot de icono inicial se reemplaza por una muestra de color circular (`.swatch`)
|
|
24
|
+
* que se posiciona absolutamente sobre una entrada de color nativa invisible.
|
|
25
|
+
* Al hacer clic en la muestra se abre el selector de color del sistema. La parte de entrada de texto
|
|
26
|
+
* muestra el código hexadecimal seleccionado y es estrictamente `readOnly`.
|
|
27
27
|
*
|
|
28
|
-
* **
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
28
|
+
* **Sincronización de estado:**
|
|
29
|
+
* El componente escucha el evento nativo `change` en la entrada de color,
|
|
30
|
+
* actualiza la propiedad `value`, y re-despacha un evento compuesto `'change'`.
|
|
31
|
+
* No escucha `input` (arrastre continuo en el selector de color) para evitar
|
|
32
|
+
* el disparo excesivo de eventos, pero los consumidores pueden adjuntar sus propios
|
|
33
|
+
* escuchas de `input` directamente al elemento si se necesita una vista previa en vivo.
|
|
34
34
|
*
|
|
35
|
-
* @fires change -
|
|
36
|
-
*
|
|
35
|
+
* @fires change - Burbujea y está compuesto. Se dispara cuando el selector de color se cierra
|
|
36
|
+
* y el valor se confirma. Leer `element.value`.
|
|
37
37
|
*
|
|
38
38
|
* @example
|
|
39
39
|
* ```html
|
|
40
40
|
* <moni-color-field
|
|
41
|
-
* label="
|
|
41
|
+
* label="Color del Tema"
|
|
42
42
|
* name="primaryColor"
|
|
43
43
|
* value="#6750a4"
|
|
44
44
|
* variant="outlined"
|
|
45
45
|
* ></moni-color-field>
|
|
46
46
|
* ```
|
|
47
47
|
*
|
|
48
|
-
* @csspart field -
|
|
49
|
-
* @csspart swatch -
|
|
50
|
-
* @csspart input-color -
|
|
51
|
-
* @csspart input-text -
|
|
52
|
-
* @csspart label -
|
|
48
|
+
* @csspart field - El contenedor div exterior `.field`.
|
|
49
|
+
* @csspart swatch - El elemento de vista previa de color circular.
|
|
50
|
+
* @csspart input-color - El `<input type="color">` nativo, visualmente oculto.
|
|
51
|
+
* @csspart input-text - El `<input type="text">` nativo que muestra el código hexadecimal.
|
|
52
|
+
* @csspart label - El elemento flotante `<label>`.
|
|
53
53
|
*/
|
|
54
54
|
@customElement('moni-color-field')
|
|
55
55
|
export class MoniColorField extends MoniElement {
|
|
56
|
+
/**
|
|
57
|
+
* El nombre del input, enviado con los datos del formulario.
|
|
58
|
+
* @type {string}
|
|
59
|
+
*/
|
|
56
60
|
@property({ reflect: true }) name = '';
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* El texto de la etiqueta flotante.
|
|
64
|
+
* @type {string}
|
|
65
|
+
*/
|
|
57
66
|
@property({ reflect: true }) label = '';
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Variante visual del campo de texto.
|
|
70
|
+
* @type {'filled' | 'outlined'}
|
|
71
|
+
* @default 'outlined'
|
|
72
|
+
*/
|
|
58
73
|
@property({ reflect: true }) variant: 'filled' | 'outlined' = 'outlined';
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Define las dimensiones del campo de texto.
|
|
77
|
+
* @type {'small' | 'medium' | 'large' | 'extra'}
|
|
78
|
+
* @default 'medium'
|
|
79
|
+
*/
|
|
59
80
|
@property({ reflect: true })
|
|
60
81
|
size: 'small' | 'medium' | 'large' | 'extra' = 'medium';
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Forma del radio del borde del campo.
|
|
85
|
+
* @type {'round' | 'square' | 'no-round'}
|
|
86
|
+
* @default 'no-round'
|
|
87
|
+
*/
|
|
61
88
|
@property({ reflect: true })
|
|
62
89
|
shape: 'round' | 'square' | 'no-round' = 'no-round';
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Deshabilita el campo de color.
|
|
93
|
+
* @type {boolean}
|
|
94
|
+
*/
|
|
63
95
|
@property({ type: Boolean, reflect: true }) disabled = false;
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Texto de ayuda mostrado debajo del campo.
|
|
99
|
+
* @type {string}
|
|
100
|
+
*/
|
|
64
101
|
@property({ reflect: true }) helper = '';
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Texto de error mostrado debajo del campo cuando `error` es true.
|
|
105
|
+
* Sobrescribe el texto de ayuda.
|
|
106
|
+
* @type {string}
|
|
107
|
+
*/
|
|
65
108
|
@property({ reflect: true, attribute: 'error-text' }) errorText = '';
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Si es true, establece el campo en un estado de error.
|
|
112
|
+
* @type {boolean}
|
|
113
|
+
*/
|
|
66
114
|
@property({ type: Boolean, reflect: true }) error = false;
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* El valor actual del color hexadecimal.
|
|
118
|
+
* @type {string}
|
|
119
|
+
* @default '#6750a4'
|
|
120
|
+
*/
|
|
67
121
|
@property({ reflect: true }) value = '#6750a4';
|
|
68
122
|
|
|
69
123
|
@query('input[type="color"]') private _colorInput!: HTMLInputElement;
|
|
70
124
|
@query('input[type="text"]') private _textInput!: HTMLInputElement;
|
|
71
125
|
|
|
126
|
+
/**
|
|
127
|
+
* Hook de ciclo de vida de Lit.
|
|
128
|
+
* Sincroniza manualmente el estado reactivo (`value`, `disabled`) con los
|
|
129
|
+
* elementos nativos del DOM subyacente. Se hace manualmente porque el input
|
|
130
|
+
* de tipo color no despacha eventos de forma natural si mutamos sus atributos.
|
|
131
|
+
*/
|
|
72
132
|
override updated(changed: Map<string, unknown>) {
|
|
73
133
|
if (changed.has('value')) {
|
|
74
134
|
if (this._colorInput) this._colorInput.value = this.value;
|
|
@@ -108,6 +168,30 @@ export class MoniColorField extends MoniElement {
|
|
|
108
168
|
`
|
|
109
169
|
];
|
|
110
170
|
|
|
171
|
+
/**
|
|
172
|
+
* Ensambla la estructura del Shadow DOM del campo de color.
|
|
173
|
+
*
|
|
174
|
+
* **Estrategia de input en capas:**
|
|
175
|
+
* Dos elementos `<input>` se apilan absolutamente:
|
|
176
|
+
* 1. `<input type="color">` (z-index: 2, opacidad: 0) — invisible pero
|
|
177
|
+
* clicable, abre el selector de color nativo del sistema operativo.
|
|
178
|
+
* 2. `<input type="text" readonly>` (z-index: 0) — visible, muestra el
|
|
179
|
+
* valor hexadecimal. `tabindex="-1"` en el input de color significa que
|
|
180
|
+
* solo el input de texto es alcanzable por teclado.
|
|
181
|
+
*
|
|
182
|
+
* El círculo `.swatch` (z-index: 1) está posicionado absolutamente en el
|
|
183
|
+
* borde inicial del input de texto y estilizado a través de `--_swatch: ${this.value}`,
|
|
184
|
+
* lo cual establece su `background-color` mediante CSS `var(--_swatch)`.
|
|
185
|
+
*
|
|
186
|
+
* **Composición de `fieldClasses`:**
|
|
187
|
+
* El mapa de clases sigue la convención de nomenclatura field-styles de BeerCSS:
|
|
188
|
+
* `field`, `label`, `fill`/`border` (variante), `small`/`large`/`extra` (tamaño),
|
|
189
|
+
* `prefix` (activa el cambio de padding inicial para la muestra), `invalid`, forma.
|
|
190
|
+
*
|
|
191
|
+
* **Renderizado condicional de etiqueta / ayuda:**
|
|
192
|
+
* Usa el centinela `nothing` de Lit para evitar renderizar nodos DOM vacíos cuando
|
|
193
|
+
* `label` o `helper` son cadenas vacías, previniendo saltos de diseño.
|
|
194
|
+
*/
|
|
111
195
|
override render() {
|
|
112
196
|
const isActive = Boolean(this.value);
|
|
113
197
|
const fieldClasses = {
|
|
@@ -17,33 +17,33 @@ describe('moni-context-menu (P3.5 — flip)', () => {
|
|
|
17
17
|
parent.remove();
|
|
18
18
|
});
|
|
19
19
|
|
|
20
|
-
it('
|
|
20
|
+
it('renderiza un <moni-menu> en el shadow DOM', async () => {
|
|
21
21
|
await el.updateComplete;
|
|
22
22
|
const menu = el.shadowRoot?.querySelector('moni-menu');
|
|
23
23
|
expect(menu).toBeTruthy();
|
|
24
24
|
});
|
|
25
25
|
|
|
26
|
-
it('
|
|
26
|
+
it('refleja placement=bottom (por defecto)', async () => {
|
|
27
27
|
await el.updateComplete;
|
|
28
28
|
expect(el.placement).toBe('bottom');
|
|
29
29
|
const menu = el.shadowRoot?.querySelector('moni-menu');
|
|
30
30
|
expect(menu?.getAttribute('placement')).toBe('bottom');
|
|
31
31
|
});
|
|
32
32
|
|
|
33
|
-
it('
|
|
33
|
+
it('refleja los cambios de placement en el menú interno', async () => {
|
|
34
34
|
el.placement = 'top';
|
|
35
35
|
await el.updateComplete;
|
|
36
36
|
const menu = el.shadowRoot?.querySelector('moni-menu');
|
|
37
37
|
expect(menu?.getAttribute('placement')).toBe('top');
|
|
38
38
|
});
|
|
39
39
|
|
|
40
|
-
it('
|
|
40
|
+
it('refleja el atributo flip en el host', async () => {
|
|
41
41
|
el.flip = true;
|
|
42
42
|
await el.updateComplete;
|
|
43
43
|
expect(el.hasAttribute('flip')).toBe(true);
|
|
44
44
|
});
|
|
45
45
|
|
|
46
|
-
it('
|
|
46
|
+
it('abre el menú al hacer clic derecho en el padre', async () => {
|
|
47
47
|
await el.updateComplete;
|
|
48
48
|
const menu = el.shadowRoot?.querySelector(
|
|
49
49
|
'moni-menu'
|
|
@@ -60,7 +60,7 @@ describe('moni-context-menu (P3.5 — flip)', () => {
|
|
|
60
60
|
expect(menu?.hasAttribute('active')).toBe(true);
|
|
61
61
|
});
|
|
62
62
|
|
|
63
|
-
it('
|
|
63
|
+
it('cierra el menú al hacer clic en el documento', async () => {
|
|
64
64
|
await el.updateComplete;
|
|
65
65
|
const menu = el.shadowRoot?.querySelector(
|
|
66
66
|
'moni-menu'
|
|
@@ -74,7 +74,7 @@ describe('moni-context-menu (P3.5 — flip)', () => {
|
|
|
74
74
|
expect(menu?.hasAttribute('active')).toBe(false);
|
|
75
75
|
});
|
|
76
76
|
|
|
77
|
-
it('
|
|
77
|
+
it('cierra el menú al presionar Escape', async () => {
|
|
78
78
|
await el.updateComplete;
|
|
79
79
|
const menu = el.shadowRoot?.querySelector(
|
|
80
80
|
'moni-menu'
|
|
@@ -88,10 +88,10 @@ describe('moni-context-menu (P3.5 — flip)', () => {
|
|
|
88
88
|
expect(menu?.hasAttribute('active')).toBe(false);
|
|
89
89
|
});
|
|
90
90
|
|
|
91
|
-
it('
|
|
92
|
-
//
|
|
93
|
-
//
|
|
94
|
-
//
|
|
91
|
+
it('no llama a showPopover (solo visual; sin API Popover)', async () => {
|
|
92
|
+
// Sanidad: el componente es solo visual. El moni-menu interior maneja
|
|
93
|
+
// el atributo active vía visibility/opacity de CSS. No hay popover nativo
|
|
94
|
+
// de cambio.
|
|
95
95
|
await el.updateComplete;
|
|
96
96
|
const menu = el.shadowRoot?.querySelector('moni-menu');
|
|
97
97
|
expect(menu?.hasAttribute('popover')).toBe(false);
|
|
@@ -11,47 +11,47 @@ import { MoniElement, sharedStyles } from './_base/index.js';
|
|
|
11
11
|
import './moni-menu.js';
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
|
-
* Material Design 3 Context Menu
|
|
14
|
+
* Componente Material Design 3 Context Menu (Menú Contextual).
|
|
15
15
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
16
|
+
* Un menú especializado que se abre en las coordenadas exactas de un evento de puntero,
|
|
17
|
+
* típicamente desencadenado por un clic derecho (evento `contextmenu`). Proporciona
|
|
18
|
+
* acciones contextuales relacionadas con el elemento específico clicado.
|
|
19
19
|
*
|
|
20
|
-
* **
|
|
20
|
+
* **Referencia de la especificación M3:** `m3-docs/components/menus/specs.md` (Menús contextuales)
|
|
21
21
|
*
|
|
22
|
-
* **
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
22
|
+
* **Mecanismo de activación:**
|
|
23
|
+
* El componente no requiere activación programática a través de una propiedad `open`.
|
|
24
|
+
* En su lugar, adjunta un detector de eventos `contextmenu` a su elemento padre
|
|
25
|
+
* durante `connectedCallback`. Cuando se hace clic derecho en el padre, el menú
|
|
26
|
+
* captura las coordenadas `clientX`/`clientY`, previene el menú contextual predeterminado
|
|
27
|
+
* del navegador, y se abre en la posición del cursor usando `position: fixed`.
|
|
28
28
|
*
|
|
29
|
-
* **
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
29
|
+
* **Comportamiento de auto-inversión (atributo `flip`):**
|
|
30
|
+
* Según las pautas de M3, los menús deben invertirse al lado opuesto del cursor
|
|
31
|
+
* si al abrirse en la `placement` solicitada causarían un desbordamiento de la
|
|
32
|
+
* ventana gráfica. Cuando `flip=true`, el componente calcula dinámicamente los límites
|
|
33
|
+
* de la ventana antes de abrir y anula `placement` si es necesario (ej., invirtiendo
|
|
34
|
+
* de `bottom` a `top` si se hace clic cerca de la parte inferior de la pantalla).
|
|
35
35
|
*
|
|
36
|
-
* **Auto-
|
|
37
|
-
*
|
|
38
|
-
*
|
|
36
|
+
* **Auto-descarte:**
|
|
37
|
+
* Se cierra automáticamente al hacer clic en cualquier lugar fuera del menú, o al
|
|
38
|
+
* presionar la tecla `Escape`.
|
|
39
39
|
*
|
|
40
40
|
* @example
|
|
41
41
|
* ```html
|
|
42
|
-
* <!--
|
|
42
|
+
* <!-- Envuelve el área de activación y el menú en un contenedor -->
|
|
43
43
|
* <div>
|
|
44
|
-
* <p>
|
|
44
|
+
* <p>Haz clic derecho para ver las opciones</p>
|
|
45
45
|
* <moni-context-menu flip>
|
|
46
|
-
* <moni-menu-item>
|
|
47
|
-
* <moni-menu-item>
|
|
46
|
+
* <moni-menu-item>Copiar</moni-menu-item>
|
|
47
|
+
* <moni-menu-item>Pegar</moni-menu-item>
|
|
48
48
|
* <moni-divider></moni-divider>
|
|
49
|
-
* <moni-menu-item>
|
|
49
|
+
* <moni-menu-item>Eliminar</moni-menu-item>
|
|
50
50
|
* </moni-context-menu>
|
|
51
51
|
* </div>
|
|
52
52
|
* ```
|
|
53
53
|
*
|
|
54
|
-
* @slot default -
|
|
54
|
+
* @slot default - Los elementos `<moni-menu-item>` que componen el menú.
|
|
55
55
|
*/
|
|
56
56
|
@customElement('moni-context-menu')
|
|
57
57
|
export class MoniContextMenu extends MoniElement {
|
|
@@ -67,8 +67,18 @@ export class MoniContextMenu extends MoniElement {
|
|
|
67
67
|
@query('moni-menu') private _menuEl?: HTMLElement;
|
|
68
68
|
|
|
69
69
|
private _target: HTMLElement | null = null;
|
|
70
|
+
/**
|
|
71
|
+
* Wrapper estático para el manejador de teclado global.
|
|
72
|
+
* Conserva la referencia exacta para desregistrar el evento en `disconnectedCallback`.
|
|
73
|
+
*/
|
|
70
74
|
private _docKeydown = (e: KeyboardEvent) => this._onDocKeydown(e);
|
|
71
75
|
|
|
76
|
+
/**
|
|
77
|
+
* Hook de inicialización (Lit).
|
|
78
|
+
* Atrapa al elemento padre directo y le inyecta `position: relative` (si era static)
|
|
79
|
+
* para que las coordenadas de despliegue del menú floten correctamente.
|
|
80
|
+
* Adjunta los eventos nativos de `contextmenu` (clic derecho) al contenedor.
|
|
81
|
+
*/
|
|
72
82
|
override connectedCallback() {
|
|
73
83
|
super.connectedCallback();
|
|
74
84
|
this._target = this.parentElement;
|
|
@@ -84,6 +94,11 @@ export class MoniContextMenu extends MoniElement {
|
|
|
84
94
|
document.addEventListener('keydown', this._docKeydown);
|
|
85
95
|
}
|
|
86
96
|
|
|
97
|
+
/**
|
|
98
|
+
* Hook de destrucción (Lit).
|
|
99
|
+
* Limpia los detectores de clic derecho y atajos de teclado para eludir memory leaks
|
|
100
|
+
* al desmontarse del DOM.
|
|
101
|
+
*/
|
|
87
102
|
override disconnectedCallback() {
|
|
88
103
|
if (this._target) {
|
|
89
104
|
this._target.removeEventListener('contextmenu', this._onContextMenu);
|
|
@@ -93,6 +108,11 @@ export class MoniContextMenu extends MoniElement {
|
|
|
93
108
|
super.disconnectedCallback();
|
|
94
109
|
}
|
|
95
110
|
|
|
111
|
+
/**
|
|
112
|
+
* Intercepta el clic derecho (`contextmenu`) del navegador de forma nativa.
|
|
113
|
+
* Previene el menú por defecto del SO y captura las coordenadas X/Y del ratón
|
|
114
|
+
* relativas al elemento anfitrión para ubicar milimétricamente el popup personalizado.
|
|
115
|
+
*/
|
|
96
116
|
private _onContextMenu = (e: MouseEvent) => {
|
|
97
117
|
e.preventDefault();
|
|
98
118
|
if (this._target) {
|
|
@@ -105,10 +125,16 @@ export class MoniContextMenu extends MoniElement {
|
|
|
105
125
|
}
|
|
106
126
|
this._resolvedPlacement = this.placement;
|
|
107
127
|
this._open = true;
|
|
108
|
-
//
|
|
128
|
+
// Después de que Lit renderice el menú, verificar el ajuste al viewport y voltear si es necesario.
|
|
109
129
|
this.updateComplete.then(() => this._maybeFlip());
|
|
110
130
|
};
|
|
111
131
|
|
|
132
|
+
/**
|
|
133
|
+
* Sistema de Colisión/Desbordamiento de Ventana.
|
|
134
|
+
* Si la directiva `flip` está habilitada, examina los límites (BoundingClientRect)
|
|
135
|
+
* del menú tras su renderizado y altera su `placement` sobre la marcha si éste
|
|
136
|
+
* colisiona con el borde del Viewport, invirtiendo top/bottom o left/right.
|
|
137
|
+
*/
|
|
112
138
|
private _maybeFlip() {
|
|
113
139
|
if (!this.flip) return;
|
|
114
140
|
const menu = this._menuEl?.shadowRoot?.querySelector('menu') as HTMLElement | null;
|
|
@@ -129,12 +155,20 @@ export class MoniContextMenu extends MoniElement {
|
|
|
129
155
|
}
|
|
130
156
|
}
|
|
131
157
|
|
|
158
|
+
/**
|
|
159
|
+
* Cierra instintivamente el menú contextual si el usuario hace clic en
|
|
160
|
+
* cualquier zona exterior al mismo.
|
|
161
|
+
*/
|
|
132
162
|
private _onDocumentClick = () => {
|
|
133
163
|
if (this._open) {
|
|
134
164
|
this._open = false;
|
|
135
165
|
}
|
|
136
166
|
};
|
|
137
167
|
|
|
168
|
+
/**
|
|
169
|
+
* Escucha la tecla Escape a nivel documento para cerrar el menú si se
|
|
170
|
+
* encuentra desplegado, cumpliendo con los estándares de accesibilidad (WAI-ARIA).
|
|
171
|
+
*/
|
|
138
172
|
private _onDocKeydown = (e: KeyboardEvent) => {
|
|
139
173
|
if (e.key === 'Escape' && this._open) {
|
|
140
174
|
this._open = false;
|
|
@@ -159,10 +193,22 @@ export class MoniContextMenu extends MoniElement {
|
|
|
159
193
|
`
|
|
160
194
|
];
|
|
161
195
|
|
|
196
|
+
/**
|
|
197
|
+
* Renderiza el menú contextual como una superposición de Popover API posicionada en las coordenadas del puntero.
|
|
198
|
+
*
|
|
199
|
+
* El `<div>` del menú usa `popover="manual"` para que aparezca en la capa superior
|
|
200
|
+
* por encima de todo el otro contenido. Sus `top` y `left` se establecen mediante propiedades personalizadas CSS
|
|
201
|
+
* `--_x` / `--_y` (inyectadas como estilo en línea) que se calculan
|
|
202
|
+
* a partir de `clientX` / `clientY` del evento `contextmenu`.
|
|
203
|
+
*
|
|
204
|
+
* El `@click` en el fondo (fuera de los límites del menú) llama a `hidePopover()`
|
|
205
|
+
* para descartar ligeramente el menú contextual. Los elementos dentro del menú deben llamar a
|
|
206
|
+
* `event.stopPropagation()` para evitar el cierre accidental al hacer clic en un elemento.
|
|
207
|
+
*/
|
|
162
208
|
override render() {
|
|
163
|
-
//
|
|
164
|
-
//
|
|
165
|
-
//
|
|
209
|
+
// Cuando el menú está abierto, preferir la ubicación resuelta (posiblemente volteada);
|
|
210
|
+
// de lo contrario, simplemente usar la ubicación solicitada por el host para que
|
|
211
|
+
// el elemento interno refleje el atributo sincrónicamente.
|
|
166
212
|
const effectivePlacement = this._open
|
|
167
213
|
? this._resolvedPlacement
|
|
168
214
|
: this.placement;
|