@moni-labs/moni-ui 0.3.1 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/custom-elements.json +5181 -1043
- package/dist/components/_base/moni-element.d.ts +16 -9
- package/dist/components/_base/moni-element.d.ts.map +1 -1
- package/dist/components/_base/moni-element.js +63 -9
- package/dist/components/index.js +2 -2
- package/dist/components/loading-shapes.d.ts +19 -0
- package/dist/components/loading-shapes.d.ts.map +1 -1
- package/dist/components/loading-shapes.js +19 -0
- package/dist/components/moni-app-bar.d.ts +72 -62
- package/dist/components/moni-app-bar.d.ts.map +1 -1
- package/dist/components/moni-app-bar.js +72 -62
- package/dist/components/moni-badge.d.ts +64 -65
- package/dist/components/moni-badge.d.ts.map +1 -1
- package/dist/components/moni-badge.js +64 -66
- package/dist/components/moni-bottom-sheet.d.ts +129 -61
- package/dist/components/moni-bottom-sheet.d.ts.map +1 -1
- package/dist/components/moni-bottom-sheet.js +217 -131
- package/dist/components/moni-button-group.d.ts +107 -29
- package/dist/components/moni-button-group.d.ts.map +1 -1
- package/dist/components/moni-button-group.js +107 -29
- package/dist/components/moni-button-segment.d.ts +53 -12
- package/dist/components/moni-button-segment.d.ts.map +1 -1
- package/dist/components/moni-button-segment.js +53 -12
- package/dist/components/moni-button.d.ts +116 -38
- package/dist/components/moni-button.d.ts.map +1 -1
- package/dist/components/moni-button.js +128 -38
- package/dist/components/moni-card.d.ts +68 -50
- package/dist/components/moni-card.d.ts.map +1 -1
- package/dist/components/moni-card.js +68 -50
- package/dist/components/moni-carousel.d.ts +471 -53
- package/dist/components/moni-carousel.d.ts.map +1 -1
- package/dist/components/moni-carousel.js +862 -264
- package/dist/components/moni-checkbox.d.ts +49 -46
- package/dist/components/moni-checkbox.d.ts.map +1 -1
- package/dist/components/moni-checkbox.js +55 -48
- package/dist/components/moni-chip.d.ts +100 -33
- package/dist/components/moni-chip.d.ts.map +1 -1
- package/dist/components/moni-chip.js +104 -34
- package/dist/components/moni-color-field.d.ts +99 -24
- package/dist/components/moni-color-field.d.ts.map +1 -1
- package/dist/components/moni-color-field.js +99 -24
- package/dist/components/moni-context-menu.d.ts +72 -26
- package/dist/components/moni-context-menu.d.ts.map +1 -1
- package/dist/components/moni-context-menu.js +76 -30
- package/dist/components/moni-dialog.d.ts +84 -59
- package/dist/components/moni-dialog.d.ts.map +1 -1
- package/dist/components/moni-dialog.js +105 -58
- package/dist/components/moni-divider.d.ts +39 -27
- package/dist/components/moni-divider.d.ts.map +1 -1
- package/dist/components/moni-divider.js +42 -30
- package/dist/components/moni-expansion.d.ts +32 -22
- package/dist/components/moni-expansion.d.ts.map +1 -1
- package/dist/components/moni-expansion.js +32 -22
- package/dist/components/moni-fab-menu.d.ts +61 -23
- package/dist/components/moni-fab-menu.d.ts.map +1 -1
- package/dist/components/moni-fab-menu.js +69 -31
- package/dist/components/moni-fab.d.ts +86 -28
- package/dist/components/moni-fab.d.ts.map +1 -1
- package/dist/components/moni-fab.js +92 -34
- package/dist/components/moni-file-field.d.ts +118 -30
- package/dist/components/moni-file-field.d.ts.map +1 -1
- package/dist/components/moni-file-field.js +118 -30
- package/dist/components/moni-icon.d.ts +40 -35
- package/dist/components/moni-icon.d.ts.map +1 -1
- package/dist/components/moni-icon.js +43 -38
- package/dist/components/moni-list-item.d.ts +46 -33
- package/dist/components/moni-list-item.d.ts.map +1 -1
- package/dist/components/moni-list-item.js +61 -41
- package/dist/components/moni-list.d.ts +30 -20
- package/dist/components/moni-list.d.ts.map +1 -1
- package/dist/components/moni-list.js +36 -21
- package/dist/components/moni-loading-indicator.d.ts +54 -22
- package/dist/components/moni-loading-indicator.d.ts.map +1 -1
- package/dist/components/moni-loading-indicator.js +54 -22
- package/dist/components/moni-menu-item.d.ts +23 -16
- package/dist/components/moni-menu-item.d.ts.map +1 -1
- package/dist/components/moni-menu-item.js +23 -16
- package/dist/components/moni-menu.d.ts +81 -28
- package/dist/components/moni-menu.d.ts.map +1 -1
- package/dist/components/moni-menu.js +81 -30
- package/dist/components/moni-morph-modal.d.ts +141 -0
- package/dist/components/moni-morph-modal.d.ts.map +1 -1
- package/dist/components/moni-morph-modal.js +295 -58
- package/dist/components/moni-nav-item.d.ts +59 -29
- package/dist/components/moni-nav-item.d.ts.map +1 -1
- package/dist/components/moni-nav-item.js +59 -29
- package/dist/components/moni-nav.d.ts +94 -35
- package/dist/components/moni-nav.d.ts.map +1 -1
- package/dist/components/moni-nav.js +94 -35
- package/dist/components/moni-progress.d.ts +99 -55
- package/dist/components/moni-progress.d.ts.map +1 -1
- package/dist/components/moni-progress.js +99 -55
- package/dist/components/moni-radio.d.ts +62 -50
- package/dist/components/moni-radio.d.ts.map +1 -1
- package/dist/components/moni-radio.js +65 -52
- package/dist/components/moni-ripple.d.ts +74 -59
- package/dist/components/moni-ripple.d.ts.map +1 -1
- package/dist/components/moni-ripple.js +74 -59
- package/dist/components/moni-segmented-button.d.ts +91 -16
- package/dist/components/moni-segmented-button.d.ts.map +1 -1
- package/dist/components/moni-segmented-button.js +94 -17
- package/dist/components/moni-select-option.d.ts +30 -23
- package/dist/components/moni-select-option.d.ts.map +1 -1
- package/dist/components/moni-select-option.js +30 -23
- package/dist/components/moni-select.d.ts +300 -35
- package/dist/components/moni-select.d.ts.map +1 -1
- package/dist/components/moni-select.js +323 -39
- package/dist/components/moni-side-sheet.d.ts +94 -32
- package/dist/components/moni-side-sheet.d.ts.map +1 -1
- package/dist/components/moni-side-sheet.js +94 -32
- package/dist/components/moni-slider.d.ts +152 -41
- package/dist/components/moni-slider.d.ts.map +1 -1
- package/dist/components/moni-slider.js +154 -42
- package/dist/components/moni-snackbar.d.ts +53 -43
- package/dist/components/moni-snackbar.d.ts.map +1 -1
- package/dist/components/moni-snackbar.js +53 -43
- package/dist/components/moni-split-button.d.ts +63 -18
- package/dist/components/moni-split-button.d.ts.map +1 -1
- package/dist/components/moni-split-button.js +63 -18
- package/dist/components/moni-step.d.ts +36 -24
- package/dist/components/moni-step.d.ts.map +1 -1
- package/dist/components/moni-step.js +41 -29
- package/dist/components/moni-stepper.d.ts +64 -27
- package/dist/components/moni-stepper.d.ts.map +1 -1
- package/dist/components/moni-stepper.js +72 -34
- package/dist/components/moni-switch.d.ts +57 -46
- package/dist/components/moni-switch.d.ts.map +1 -1
- package/dist/components/moni-switch.js +59 -47
- package/dist/components/moni-tab.d.ts +26 -18
- package/dist/components/moni-tab.d.ts.map +1 -1
- package/dist/components/moni-tab.js +29 -21
- package/dist/components/moni-tabs.d.ts +34 -28
- package/dist/components/moni-tabs.d.ts.map +1 -1
- package/dist/components/moni-tabs.js +34 -28
- package/dist/components/moni-text-field.d.ts +139 -29
- package/dist/components/moni-text-field.d.ts.map +1 -1
- package/dist/components/moni-text-field.js +157 -31
- package/dist/components/moni-textarea.d.ts +127 -29
- package/dist/components/moni-textarea.d.ts.map +1 -1
- package/dist/components/moni-textarea.js +131 -32
- package/dist/components/moni-time-picker.d.ts +114 -24
- package/dist/components/moni-time-picker.d.ts.map +1 -1
- package/dist/components/moni-time-picker.js +127 -33
- package/dist/components/moni-toolbar.d.ts +37 -23
- package/dist/components/moni-toolbar.d.ts.map +1 -1
- package/dist/components/moni-toolbar.js +37 -23
- package/dist/components/moni-tooltip.d.ts +100 -36
- package/dist/components/moni-tooltip.d.ts.map +1 -1
- package/dist/components/moni-tooltip.js +104 -40
- package/dist/components/moni-typography.d.ts +68 -30
- package/dist/components/moni-typography.d.ts.map +1 -1
- package/dist/components/moni-typography.js +70 -32
- package/dist/styles/tokens.css +7 -7
- package/dist/types/events.d.ts +17 -0
- package/dist/types/events.d.ts.map +1 -0
- package/dist/types/events.js +1 -0
- package/dist/utils/event-emitter.d.ts +13 -0
- package/dist/utils/event-emitter.d.ts.map +1 -0
- package/dist/utils/event-emitter.js +13 -0
- package/package.json +2 -1
- package/src/components/_base/moni-element.ts +73 -9
- package/src/components/index.ts +2 -2
- package/src/components/loading-shapes.ts +19 -0
- package/src/components/moni-app-bar.test.ts +10 -10
- package/src/components/moni-app-bar.ts +72 -62
- package/src/components/moni-badge.ts +64 -66
- package/src/components/moni-bottom-sheet.test.ts +39 -45
- package/src/components/moni-bottom-sheet.ts +222 -131
- package/src/components/moni-button-group.test.ts +14 -14
- package/src/components/moni-button-group.ts +107 -29
- package/src/components/moni-button-segment.ts +53 -12
- package/src/components/moni-button.test.ts +28 -26
- package/src/components/moni-button.ts +139 -39
- package/src/components/moni-card.test.ts +6 -6
- package/src/components/moni-card.ts +70 -50
- package/src/components/moni-carousel.test.ts +12 -12
- package/src/components/moni-carousel.ts +953 -290
- package/src/components/moni-checkbox.test.ts +7 -7
- package/src/components/moni-checkbox.ts +62 -48
- package/src/components/moni-chip.test.ts +17 -17
- package/src/components/moni-chip.ts +112 -34
- package/src/components/moni-color-field.test.ts +5 -5
- package/src/components/moni-color-field.ts +108 -24
- package/src/components/moni-context-menu.test.ts +11 -11
- package/src/components/moni-context-menu.ts +76 -30
- package/src/components/moni-dialog.ts +108 -59
- package/src/components/moni-divider.test.ts +4 -4
- package/src/components/moni-divider.ts +42 -30
- package/src/components/moni-expansion.ts +32 -22
- package/src/components/moni-fab-menu.test.ts +11 -11
- package/src/components/moni-fab-menu.ts +69 -31
- package/src/components/moni-fab.test.ts +16 -16
- package/src/components/moni-fab.ts +100 -34
- package/src/components/moni-file-field.test.ts +8 -8
- package/src/components/moni-file-field.ts +132 -30
- package/src/components/moni-icon.test.ts +11 -11
- package/src/components/moni-icon.ts +43 -38
- package/src/components/moni-list-item.test.ts +10 -10
- package/src/components/moni-list-item.ts +61 -41
- package/src/components/moni-list.ts +37 -21
- package/src/components/moni-loading-indicator.test.ts +3 -3
- package/src/components/moni-loading-indicator.ts +54 -22
- package/src/components/moni-menu-item.ts +23 -16
- package/src/components/moni-menu.test.ts +7 -7
- package/src/components/moni-menu.ts +87 -30
- package/src/components/moni-morph-modal.test.ts +18 -17
- package/src/components/moni-morph-modal.ts +327 -60
- package/src/components/moni-nav-item.ts +59 -29
- package/src/components/moni-nav.test.ts +11 -11
- package/src/components/moni-nav.ts +94 -35
- package/src/components/moni-progress.test.ts +9 -9
- package/src/components/moni-progress.ts +100 -56
- package/src/components/moni-radio.test.ts +8 -8
- package/src/components/moni-radio.ts +71 -51
- package/src/components/moni-ripple.ts +74 -59
- package/src/components/moni-segmented-button.test.ts +4 -4
- package/src/components/moni-segmented-button.ts +94 -17
- package/src/components/moni-select-option.ts +30 -23
- package/src/components/moni-select.test.ts +11 -11
- package/src/components/moni-select.ts +361 -50
- package/src/components/moni-side-sheet.test.ts +7 -7
- package/src/components/moni-side-sheet.ts +94 -32
- package/src/components/moni-slider.test.ts +7 -7
- package/src/components/moni-slider.ts +165 -42
- package/src/components/moni-snackbar.test.ts +8 -8
- package/src/components/moni-snackbar.ts +53 -43
- package/src/components/moni-split-button.ts +63 -18
- package/src/components/moni-step.test.ts +7 -7
- package/src/components/moni-step.ts +41 -29
- package/src/components/moni-stepper.test.ts +7 -7
- package/src/components/moni-stepper.ts +72 -34
- package/src/components/moni-switch.test.ts +12 -12
- package/src/components/moni-switch.ts +66 -47
- package/src/components/moni-tab.test.ts +5 -5
- package/src/components/moni-tab.ts +29 -21
- package/src/components/moni-tabs.ts +34 -28
- package/src/components/moni-text-field.test.ts +13 -13
- package/src/components/moni-text-field.ts +181 -30
- package/src/components/moni-textarea.test.ts +17 -17
- package/src/components/moni-textarea.ts +155 -31
- package/src/components/moni-time-picker.test.ts +5 -5
- package/src/components/moni-time-picker.ts +128 -33
- package/src/components/moni-toolbar.test.ts +8 -8
- package/src/components/moni-toolbar.ts +37 -23
- package/src/components/moni-tooltip.test.ts +15 -15
- package/src/components/moni-tooltip.ts +107 -40
- package/src/components/moni-typography.test.ts +10 -10
- package/src/components/moni-typography.ts +73 -32
- package/src/styles/tokens.css +7 -7
- package/src/types/events.ts +17 -0
- package/src/utils/event-emitter.ts +26 -0
|
@@ -14,81 +14,192 @@ import './moni-icon.js';
|
|
|
14
14
|
import './moni-progress.js';
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
|
-
* Material Design 3 Textarea
|
|
17
|
+
* Componente Material Design 3 Textarea (Área de texto).
|
|
18
18
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
19
|
+
* Un campo de entrada de texto multilínea diseñado para recolectar cantidades mayores de texto,
|
|
20
|
+
* como comentarios, descripciones o mensajes.
|
|
21
21
|
*
|
|
22
|
-
* **
|
|
22
|
+
* **Referencia a la especificación M3:** `m3-docs/components/text-fields/specs.md`
|
|
23
23
|
*
|
|
24
|
-
* **
|
|
25
|
-
*
|
|
26
|
-
* `<moni-text-field>`,
|
|
27
|
-
*
|
|
28
|
-
*
|
|
24
|
+
* **Arquitectura visual:**
|
|
25
|
+
* Comparte exactamente el mismo contenedor `.field` y motor de estilos que
|
|
26
|
+
* `<moni-text-field>`, pero internamente renderiza un `<textarea>` nativo en lugar
|
|
27
|
+
* de un `<input>`. Esto asegura la consistencia visual en todos los elementos del formulario
|
|
28
|
+
* en cuanto a etiquetas flotantes, texto de ayuda, estados de error e iconos.
|
|
29
29
|
*
|
|
30
|
-
* **
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
* trailing
|
|
34
|
-
*
|
|
30
|
+
* **Contador de caracteres:**
|
|
31
|
+
* Si se establece el atributo `maxlength`, el área de texto muestra automáticamente
|
|
32
|
+
* un contador de caracteres (`{longitud actual} / {maxlength}`) ubicado en el
|
|
33
|
+
* borde final (trailing) del área de texto de soporte (abajo a la derecha). Esto puede
|
|
34
|
+
* suprimirse estableciendo el atributo `no-counter`.
|
|
35
35
|
*
|
|
36
|
-
* **
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* `@change
|
|
40
|
-
*
|
|
41
|
-
* textarea.
|
|
36
|
+
* **Gestión del estado:**
|
|
37
|
+
* Este componente es puramente visual y representacional. Refleja los atributos
|
|
38
|
+
* hacia el textarea nativo, pero NO adjunta listeners internos para `@input` o
|
|
39
|
+
* `@change`. Los consumidores deben adjuntar listeners estándar del DOM directamente
|
|
40
|
+
* a este elemento para capturar la entrada del usuario, tal como lo harían con un
|
|
41
|
+
* textarea nativo.
|
|
42
42
|
*
|
|
43
43
|
* @example
|
|
44
44
|
* ```html
|
|
45
|
-
* <!--
|
|
46
|
-
* <moni-textarea label="
|
|
45
|
+
* <!-- Textarea llenado (filled) estándar -->
|
|
46
|
+
* <moni-textarea label="Descripción" rows="4"></moni-textarea>
|
|
47
47
|
*
|
|
48
|
-
* <!--
|
|
48
|
+
* <!-- Textarea contorneado (outlined) con contador de caracteres -->
|
|
49
49
|
* <moni-textarea
|
|
50
50
|
* variant="outlined"
|
|
51
|
-
* label="
|
|
51
|
+
* label="Biografía"
|
|
52
52
|
* maxlength="160"
|
|
53
53
|
* ></moni-textarea>
|
|
54
54
|
* ```
|
|
55
55
|
*
|
|
56
|
-
* @csspart field -
|
|
57
|
-
* @csspart input -
|
|
58
|
-
* @csspart label -
|
|
59
|
-
* @csspart helper -
|
|
60
|
-
* @csspart counter -
|
|
56
|
+
* @csspart field - El contenedor div `.field` exterior.
|
|
57
|
+
* @csspart input - El elemento `<textarea>` nativo.
|
|
58
|
+
* @csspart label - El elemento `<label>` flotante.
|
|
59
|
+
* @csspart helper - El área de texto de ayuda/error.
|
|
60
|
+
* @csspart counter - El elemento contador de caracteres.
|
|
61
61
|
*/
|
|
62
62
|
@customElement('moni-textarea')
|
|
63
63
|
export class MoniTextarea extends MoniElement {
|
|
64
|
+
static formAssociated = true;
|
|
65
|
+
private _internals: ElementInternals;
|
|
66
|
+
|
|
67
|
+
constructor() {
|
|
68
|
+
super();
|
|
69
|
+
this._internals = this.attachInternals();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* El nombre del textarea, enviado con los datos del formulario.
|
|
74
|
+
* @type {string}
|
|
75
|
+
*/
|
|
64
76
|
@property({ reflect: true }) name = '';
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* El texto de la etiqueta flotante.
|
|
80
|
+
* @type {string}
|
|
81
|
+
*/
|
|
65
82
|
@property({ reflect: true }) label = '';
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Variante visual del área de texto.
|
|
86
|
+
* @type {'filled' | 'outlined'}
|
|
87
|
+
* @default 'filled'
|
|
88
|
+
*/
|
|
66
89
|
@property({ reflect: true }) variant: 'filled' | 'outlined' = 'filled';
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Define las dimensiones del área de texto.
|
|
93
|
+
* @type {'small' | 'medium' | 'large' | 'extra'}
|
|
94
|
+
* @default 'medium'
|
|
95
|
+
*/
|
|
67
96
|
@property({ reflect: true })
|
|
68
97
|
size: 'small' | 'medium' | 'large' | 'extra' = 'medium';
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Forma del radio del borde (border-radius) del campo.
|
|
101
|
+
* @type {'round' | 'square' | 'no-round'}
|
|
102
|
+
* @default 'no-round'
|
|
103
|
+
*/
|
|
69
104
|
@property({ reflect: true })
|
|
70
105
|
shape: 'round' | 'square' | 'no-round' = 'no-round';
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Nombre del icono inicial (leading) (Material Symbols).
|
|
109
|
+
* @type {string}
|
|
110
|
+
*/
|
|
71
111
|
@property({ reflect: true }) icon = '';
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Nombre del icono final (trailing) (Material Symbols).
|
|
115
|
+
* @type {string}
|
|
116
|
+
*/
|
|
72
117
|
@property({ reflect: true, attribute: 'trailing-icon' }) trailingIcon = '';
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Prefijo de texto corto mostrado antes del valor del input.
|
|
121
|
+
* @type {string}
|
|
122
|
+
*/
|
|
73
123
|
@property({ reflect: true }) prefix = '';
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Sufijo de texto corto mostrado después del valor del input.
|
|
127
|
+
* @type {string}
|
|
128
|
+
*/
|
|
74
129
|
@property({ reflect: true }) suffix = '';
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Número por defecto de líneas de texto visibles.
|
|
133
|
+
* @type {number}
|
|
134
|
+
* @default 3
|
|
135
|
+
*/
|
|
75
136
|
@property({ type: Number, reflect: true }) rows = 3;
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Número máximo de caracteres permitidos en el área de texto.
|
|
140
|
+
* También habilita la visualización del contador de caracteres a menos que `noCounter` sea true.
|
|
141
|
+
* @type {number | null}
|
|
142
|
+
*/
|
|
76
143
|
@property({ type: Number, reflect: true }) maxlength: number | null = null;
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Oculta la visualización del contador de caracteres cuando se establece `maxlength`.
|
|
147
|
+
* @type {boolean}
|
|
148
|
+
*/
|
|
77
149
|
@property({ type: Boolean, reflect: true, attribute: 'no-counter' })
|
|
78
150
|
noCounter = false;
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Si es true, muestra un indicador de carga (progreso circular) al final.
|
|
154
|
+
* @type {boolean}
|
|
155
|
+
*/
|
|
79
156
|
@property({ type: Boolean, reflect: true }) loading = false;
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Deshabilita el área de texto.
|
|
160
|
+
* @type {boolean}
|
|
161
|
+
*/
|
|
80
162
|
@property({ type: Boolean, reflect: true }) disabled = false;
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Texto de ayuda mostrado debajo del campo.
|
|
166
|
+
* @type {string}
|
|
167
|
+
*/
|
|
81
168
|
@property({ reflect: true }) helper = '';
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Texto de error mostrado debajo del campo cuando `error` es true.
|
|
172
|
+
* Sobrescribe el texto de ayuda.
|
|
173
|
+
* @type {string}
|
|
174
|
+
*/
|
|
82
175
|
@property({ reflect: true, attribute: 'error-text' }) errorText = '';
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Si es true, establece el campo en un estado de error.
|
|
179
|
+
* @type {boolean}
|
|
180
|
+
*/
|
|
83
181
|
@property({ type: Boolean, reflect: true }) error = false;
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* El valor actual del área de texto.
|
|
185
|
+
* @type {string}
|
|
186
|
+
*/
|
|
84
187
|
@property({ reflect: true }) value = '';
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Texto de marcador de posición (placeholder) mostrado cuando el textarea está vacío y la etiqueta es flotante.
|
|
191
|
+
* @type {string}
|
|
192
|
+
*/
|
|
85
193
|
@property({ reflect: true }) placeholder = '';
|
|
86
194
|
|
|
87
195
|
@query('textarea') private _input!: HTMLTextAreaElement;
|
|
88
196
|
|
|
89
197
|
override updated(changed: Map<string, unknown>) {
|
|
90
198
|
if (this._input) {
|
|
91
|
-
if (changed.has('value'))
|
|
199
|
+
if (changed.has('value')) {
|
|
200
|
+
this._input.value = this.value;
|
|
201
|
+
this._internals?.setFormValue?.(this.value);
|
|
202
|
+
}
|
|
92
203
|
if (changed.has('disabled')) this._input.disabled = this.disabled;
|
|
93
204
|
if (changed.has('maxlength') && this.maxlength != null) {
|
|
94
205
|
this._input.maxLength = this.maxlength;
|
|
@@ -98,6 +209,19 @@ export class MoniTextarea extends MoniElement {
|
|
|
98
209
|
|
|
99
210
|
static override styles = [sharedStyles, fieldStyles];
|
|
100
211
|
|
|
212
|
+
/**
|
|
213
|
+
* Renderiza el campo del área de texto con etiqueta, iconos de prefijo/sufijo y contador de caracteres.
|
|
214
|
+
*
|
|
215
|
+
* **Composición de `fieldClasses`:**
|
|
216
|
+
* Sigue la convención de nomenclatura field-styles. `prefix` se añade
|
|
217
|
+
* cuando el texto de `icon` o `prefix` está presente (desplaza el inicio en línea de la etiqueta).
|
|
218
|
+
* `suffix` se añade cuando `trailingIcon`, el texto `suffix` o `loading` es true.
|
|
219
|
+
*
|
|
220
|
+
* **Contador de caracteres:**
|
|
221
|
+
* `showCounter` es true cuando `maxlength > 0` y `noCounter` no está configurado.
|
|
222
|
+
* El contador muestra `${this.value.length} / ${this.maxlength}` y puede volverse rojo
|
|
223
|
+
* (vía CSS `invalid`) dependiendo de la validación.
|
|
224
|
+
*/
|
|
101
225
|
override render() {
|
|
102
226
|
const hasLeading = Boolean(this.icon) || Boolean(this.prefix);
|
|
103
227
|
const hasTrailing =
|
|
@@ -152,7 +276,7 @@ export class MoniTextarea extends MoniElement {
|
|
|
152
276
|
>`
|
|
153
277
|
: nothing;
|
|
154
278
|
|
|
155
|
-
// M3
|
|
279
|
+
// Especificación M3: texto de soporte a la izquierda, contador de caracteres a la derecha.
|
|
156
280
|
const counter = showCounter
|
|
157
281
|
? html`<output part="counter" class="counter"
|
|
158
282
|
>${this.value.length} / ${this.maxlength}</output
|
|
@@ -14,21 +14,21 @@ describe('moni-time-picker', () => {
|
|
|
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.value).toBe('00:00');
|
|
20
20
|
expect(el.mode).toBe('dial');
|
|
21
21
|
expect(el.use24Hour).toBe(false);
|
|
22
22
|
});
|
|
23
23
|
|
|
24
|
-
it('
|
|
24
|
+
it('analiza el valor de entrada correctamente', async () => {
|
|
25
25
|
el.value = '14:45';
|
|
26
26
|
await el.updateComplete;
|
|
27
|
-
//
|
|
27
|
+
// Como use24Hour es false, PM está establecido
|
|
28
28
|
expect(el.value).toBe('14:45');
|
|
29
29
|
});
|
|
30
30
|
|
|
31
|
-
it('
|
|
31
|
+
it('alterna el modo', async () => {
|
|
32
32
|
await el.updateComplete;
|
|
33
33
|
const toggleBtn = el.shadowRoot?.querySelector('.mode-toggle-btn') as HTMLButtonElement;
|
|
34
34
|
expect(toggleBtn).toBeTruthy();
|
|
@@ -42,7 +42,7 @@ describe('moni-time-picker', () => {
|
|
|
42
42
|
expect(el.mode).toBe('dial');
|
|
43
43
|
});
|
|
44
44
|
|
|
45
|
-
it('
|
|
45
|
+
it('permite escribir la hora en modo input', async () => {
|
|
46
46
|
el.mode = 'input';
|
|
47
47
|
el.use24Hour = true;
|
|
48
48
|
await el.updateComplete;
|
|
@@ -12,40 +12,40 @@ import './moni-icon.js';
|
|
|
12
12
|
import './moni-button.js';
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
* Material Design 3 Time Picker
|
|
15
|
+
* Componente Material Design 3 Time Picker (Selector de hora).
|
|
16
16
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* 1. **
|
|
20
|
-
*
|
|
21
|
-
* 2. **
|
|
17
|
+
* Un control altamente interactivo que permite a los usuarios seleccionar una hora específica.
|
|
18
|
+
* Proporciona dos modos de entrada distintos:
|
|
19
|
+
* 1. **Modo dial (analógico):** Una carátula de reloj interactiva donde los usuarios pueden arrastrar o hacer clic
|
|
20
|
+
* para seleccionar horas y minutos.
|
|
21
|
+
* 2. **Modo input (texto):** Entradas de texto estándar para una introducción precisa por teclado.
|
|
22
22
|
*
|
|
23
|
-
* **
|
|
23
|
+
* **Referencia a la especificación M3:** `m3-docs/components/time-pickers/specs.md`
|
|
24
24
|
*
|
|
25
|
-
* **
|
|
26
|
-
* -
|
|
27
|
-
* (`HH:MM`,
|
|
28
|
-
* -
|
|
29
|
-
*
|
|
30
|
-
*
|
|
25
|
+
* **Formatos de hora y modos:**
|
|
26
|
+
* - La propiedad `value` espera y siempre emite un string en formato de 24 horas
|
|
27
|
+
* (`HH:MM`, ej. `"14:30"`).
|
|
28
|
+
* - Establecer `use-24-hour` configura la presentación visual para usar un
|
|
29
|
+
* reloj de 24 horas (anillos interior y exterior) y elimina el selector AM/PM. De lo contrario,
|
|
30
|
+
* utiliza un dial estándar de 12 horas con un selector AM/PM.
|
|
31
31
|
*
|
|
32
|
-
* **
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
32
|
+
* **Diseño responsivo:**
|
|
33
|
+
* El atributo `orientation` configura el diseño. `vertical` apila la
|
|
34
|
+
* visualización de la hora sobre la carátula del reloj, `horizontal` los coloca lado a lado,
|
|
35
|
+
* y `auto` responde automáticamente al ancho del contenedor/viewport.
|
|
36
36
|
*
|
|
37
|
-
* @fires change -
|
|
38
|
-
* `detail.value`
|
|
39
|
-
* @fires cancel -
|
|
40
|
-
* @fires ok -
|
|
41
|
-
*
|
|
37
|
+
* @fires change - Se dispara cuando la hora seleccionada cambia interactivamente. El
|
|
38
|
+
* `detail.value` contiene la nueva hora en formato `HH:MM`.
|
|
39
|
+
* @fires cancel - Se dispara cuando se hace clic en el botón 'Cancelar'.
|
|
40
|
+
* @fires ok - Se dispara cuando se hace clic en el botón 'OK'. El `detail.value`
|
|
41
|
+
* contiene la hora final confirmada.
|
|
42
42
|
*
|
|
43
43
|
* @example
|
|
44
44
|
* ```html
|
|
45
|
-
* <!-- 12
|
|
45
|
+
* <!-- Formato 12 horas (AM/PM) -->
|
|
46
46
|
* <moni-time-picker value="14:30"></moni-time-picker>
|
|
47
47
|
*
|
|
48
|
-
* <!-- 24
|
|
48
|
+
* <!-- Formato 24 horas -->
|
|
49
49
|
* <moni-time-picker use-24-hour value="14:30"></moni-time-picker>
|
|
50
50
|
* ```
|
|
51
51
|
*/
|
|
@@ -66,12 +66,24 @@ export class MoniTimePicker extends MoniElement {
|
|
|
66
66
|
|
|
67
67
|
private isDragging = false;
|
|
68
68
|
|
|
69
|
+
/**
|
|
70
|
+
* Hook del ciclo de vida (Lit) previo al renderizado.
|
|
71
|
+
*
|
|
72
|
+
* Si la propiedad externa `value` o el modo `use24Hour` cambian (vía binding o atributo HTML),
|
|
73
|
+
* dispara el `parseValue()` de inmediato para mantener sincronizado el estado interno de
|
|
74
|
+
* horas y minutos (y recalcular AM/PM) antes de mutar el DOM real.
|
|
75
|
+
*/
|
|
69
76
|
protected override willUpdate(changedProperties: PropertyValues) {
|
|
70
77
|
if (changedProperties.has('value') || changedProperties.has('use24Hour')) {
|
|
71
78
|
this.parseValue();
|
|
72
79
|
}
|
|
73
80
|
}
|
|
74
81
|
|
|
82
|
+
/**
|
|
83
|
+
* Interpreta el string `value` (formato "HH:MM") y lo descompone en enteros para
|
|
84
|
+
* el estado interno. Automáticamente corrige valores fuera de rango y determina
|
|
85
|
+
* si estamos en AM o PM (cuando no se usa formato de 24 horas).
|
|
86
|
+
*/
|
|
75
87
|
private parseValue() {
|
|
76
88
|
const parts = this.value.split(':');
|
|
77
89
|
let h = parseInt(parts[0], 10);
|
|
@@ -92,6 +104,11 @@ export class MoniTimePicker extends MoniElement {
|
|
|
92
104
|
}
|
|
93
105
|
}
|
|
94
106
|
|
|
107
|
+
/**
|
|
108
|
+
* Reconstruye el string `value` a partir del estado interno (`currentHour`, `currentMinute`).
|
|
109
|
+
* Formatea con ceros a la izquierda e incluye la lógica de conversión AM/PM a 24hrs
|
|
110
|
+
* para garantizar que el valor expuesto hacia afuera sea siempre un estándar ISO ("14:30").
|
|
111
|
+
*/
|
|
95
112
|
private updateValue() {
|
|
96
113
|
let h = this.currentHour;
|
|
97
114
|
const m = this.currentMinute;
|
|
@@ -101,7 +118,7 @@ export class MoniTimePicker extends MoniElement {
|
|
|
101
118
|
if (h < 12) h += 12;
|
|
102
119
|
} else {
|
|
103
120
|
if (h === 12) h = 0;
|
|
104
|
-
else if (h > 12) h -= 12; //
|
|
121
|
+
else if (h > 12) h -= 12; // Ajuste por si quedó fuera de límites
|
|
105
122
|
}
|
|
106
123
|
}
|
|
107
124
|
|
|
@@ -116,20 +133,41 @@ export class MoniTimePicker extends MoniElement {
|
|
|
116
133
|
}));
|
|
117
134
|
}
|
|
118
135
|
|
|
136
|
+
/**
|
|
137
|
+
* Alterna el modo de interacción visual entre el Reloj Analógico (dial)
|
|
138
|
+
* y el modo de Entrada de Texto manual (input).
|
|
139
|
+
*/
|
|
119
140
|
private toggleMode() {
|
|
120
141
|
this.mode = this.mode === 'dial' ? 'input' : 'dial';
|
|
121
142
|
}
|
|
122
143
|
|
|
144
|
+
/**
|
|
145
|
+
* Define el nivel de selección activo ('hour' o 'minute').
|
|
146
|
+
* Cambia dinámicamente qué anillo o qué matemáticas (12 vs 60 items)
|
|
147
|
+
* utilizará el componente principal y el reloj.
|
|
148
|
+
*/
|
|
123
149
|
private setSelection(type: 'hour' | 'minute') {
|
|
124
150
|
this.activeSelection = type;
|
|
125
151
|
}
|
|
126
152
|
|
|
153
|
+
/**
|
|
154
|
+
* Cambia forzosamente el periodo del día ('AM' o 'PM') cuando el usuario
|
|
155
|
+
* presiona los conmutadores laterales (sólo visible en formato 12h).
|
|
156
|
+
* Inmediatamente propaga el cambio hacia `updateValue()` para recalcular
|
|
157
|
+
* y despachar la hora formateada.
|
|
158
|
+
*/
|
|
127
159
|
private setPeriod(p: 'AM' | 'PM') {
|
|
128
160
|
this.period = p;
|
|
129
161
|
this.updateValue();
|
|
130
162
|
}
|
|
131
163
|
|
|
132
164
|
// Clock Math and Interaction
|
|
165
|
+
/**
|
|
166
|
+
* Inicia el proceso de arrastre en la carátula del reloj (Pointer Down).
|
|
167
|
+
* Utiliza `setPointerCapture` nativo para asegurar que el movimiento (drag) siga
|
|
168
|
+
* siendo rastreado aunque el puntero del usuario salga físicamente del contenedor,
|
|
169
|
+
* garantizando una interacción "Touch" a prueba de errores.
|
|
170
|
+
*/
|
|
133
171
|
private handleClockPointerDown(e: PointerEvent) {
|
|
134
172
|
if (!this.clockFaceEl) return;
|
|
135
173
|
this.isDragging = true;
|
|
@@ -138,42 +176,52 @@ export class MoniTimePicker extends MoniElement {
|
|
|
138
176
|
this.handleClockPointerMove(e);
|
|
139
177
|
}
|
|
140
178
|
|
|
179
|
+
/**
|
|
180
|
+
* Corazón matemático del reloj radial (Time Picker analógico).
|
|
181
|
+
* Convierte las coordenadas cartesianas del ratón/dedo en un ángulo polar (0-360º),
|
|
182
|
+
* y dependiendo si medimos horas o minutos, lo mapea al número correspondiente.
|
|
183
|
+
*/
|
|
141
184
|
private handleClockPointerMove(e: PointerEvent) {
|
|
142
185
|
if (!this.isDragging || !this.clockFaceEl) return;
|
|
186
|
+
|
|
143
187
|
const rect = this.clockFaceEl.getBoundingClientRect();
|
|
188
|
+
// Encontramos el centro geométrico absoluto del reloj
|
|
144
189
|
const centerX = rect.left + rect.width / 2;
|
|
145
190
|
const centerY = rect.top + rect.height / 2;
|
|
146
191
|
|
|
147
192
|
const dx = e.clientX - centerX;
|
|
148
193
|
const dy = e.clientY - centerY;
|
|
194
|
+
// Teorema de Pitágoras para saber a qué distancia del centro está apuntando el usuario
|
|
149
195
|
const distance = Math.sqrt(dx * dx + dy * dy);
|
|
150
196
|
|
|
151
|
-
//
|
|
197
|
+
// Calculamos el ángulo en grados partiendo desde las 12 (sentido horario).
|
|
198
|
+
// Math.atan2 devuelve de -PI a PI, sumamos 90º para desfasar el origen arriba (eje Y).
|
|
152
199
|
let angle = Math.atan2(dy, dx) * (180 / Math.PI) + 90;
|
|
153
200
|
if (angle < 0) angle += 360;
|
|
154
201
|
|
|
155
202
|
if (this.activeSelection === 'hour') {
|
|
156
203
|
if (this.use24Hour) {
|
|
157
|
-
//
|
|
204
|
+
// Reloj de 24 horas M3: Un círculo externo (13-00) y uno interno (1-12)
|
|
205
|
+
// El umbral (0.32) fue medido visualmente para coincidir con el diseño radial interno.
|
|
158
206
|
const isInner = distance < rect.width * 0.32;
|
|
159
|
-
let hour = Math.round(angle / 30) % 12;
|
|
207
|
+
let hour = Math.round(angle / 30) % 12; // 360 / 12 horas = 30 grados por hora
|
|
160
208
|
if (hour === 0) hour = 12;
|
|
161
209
|
|
|
162
210
|
if (isInner) {
|
|
163
|
-
//
|
|
211
|
+
// Círculo interno: 1 a 12 (AM/PM)
|
|
164
212
|
this.currentHour = hour;
|
|
165
213
|
} else {
|
|
166
|
-
//
|
|
214
|
+
// Círculo externo: 13 a 24 (donde las 24 = 0)
|
|
167
215
|
this.currentHour = hour === 12 ? 0 : hour + 12;
|
|
168
216
|
}
|
|
169
217
|
} else {
|
|
170
|
-
// 12
|
|
218
|
+
// Reloj estándar de 12 horas: solo 1 a 12
|
|
171
219
|
let hour = Math.round(angle / 30) % 12;
|
|
172
220
|
if (hour === 0) hour = 12;
|
|
173
221
|
this.currentHour = hour;
|
|
174
222
|
}
|
|
175
223
|
} else {
|
|
176
|
-
//
|
|
224
|
+
// Modo minutos: 360 / 60 minutos = 6 grados por minuto
|
|
177
225
|
const minute = Math.round(angle / 6) % 60;
|
|
178
226
|
this.currentMinute = minute;
|
|
179
227
|
}
|
|
@@ -181,12 +229,19 @@ export class MoniTimePicker extends MoniElement {
|
|
|
181
229
|
this.updateValue();
|
|
182
230
|
}
|
|
183
231
|
|
|
232
|
+
/**
|
|
233
|
+
* Finaliza la interacción de arrastre en la carátula del reloj (Pointer Up).
|
|
234
|
+
*
|
|
235
|
+
* Como heurística de usabilidad, si el usuario acaba de seleccionar la Hora,
|
|
236
|
+
* el componente espera 300ms y automáticamente transiciona a la vista de Minutos.
|
|
237
|
+
* Esto reduce los clics necesarios en interacciones de Time Pickers de un solo toque.
|
|
238
|
+
*/
|
|
184
239
|
private handleClockPointerUp() {
|
|
185
240
|
if (this.isDragging) {
|
|
186
241
|
this.isDragging = false;
|
|
187
242
|
this.clockFaceEl?.classList.remove('dragging');
|
|
188
243
|
if (this.activeSelection === 'hour') {
|
|
189
|
-
//
|
|
244
|
+
// Cambiar automáticamente a la selección de minutos después de elegir la hora
|
|
190
245
|
setTimeout(() => {
|
|
191
246
|
this.activeSelection = 'minute';
|
|
192
247
|
}, 300);
|
|
@@ -194,6 +249,11 @@ export class MoniTimePicker extends MoniElement {
|
|
|
194
249
|
}
|
|
195
250
|
}
|
|
196
251
|
|
|
252
|
+
/**
|
|
253
|
+
* Handler para entradas directas desde el `<input>` de horas (Modo 'input' texto).
|
|
254
|
+
* Implementa clamping (límites mínimos y máximos) para asegurar que el usuario
|
|
255
|
+
* nunca pueda introducir valores erróneos mayores a 23h o menores a 0h.
|
|
256
|
+
*/
|
|
197
257
|
private handleHourInputChange(e: Event) {
|
|
198
258
|
const target = e.target as HTMLInputElement;
|
|
199
259
|
let val = parseInt(target.value, 10);
|
|
@@ -211,6 +271,10 @@ export class MoniTimePicker extends MoniElement {
|
|
|
211
271
|
this.updateValue();
|
|
212
272
|
}
|
|
213
273
|
|
|
274
|
+
/**
|
|
275
|
+
* Handler para entradas directas desde el `<input>` de minutos (Modo 'input' texto).
|
|
276
|
+
* Trunca cualquier input alfanumérico a enteros y realiza un clamp a 0-59.
|
|
277
|
+
*/
|
|
214
278
|
private handleMinuteInputChange(e: Event) {
|
|
215
279
|
const target = e.target as HTMLInputElement;
|
|
216
280
|
let val = parseInt(target.value, 10);
|
|
@@ -598,6 +662,13 @@ export class MoniTimePicker extends MoniElement {
|
|
|
598
662
|
`
|
|
599
663
|
];
|
|
600
664
|
|
|
665
|
+
/**
|
|
666
|
+
* Renderizador de la carátula circular (Dial Face).
|
|
667
|
+
*
|
|
668
|
+
* Utiliza trigonometría básica (`sin` y `cos`) para distribuir los números equitativamente
|
|
669
|
+
* a lo largo del perímetro del círculo en CSS absoluto. En formato 24h, renderiza
|
|
670
|
+
* dos anillos concéntricos manipulando el radio relativo (`50%` vs `32%`).
|
|
671
|
+
*/
|
|
601
672
|
private renderDialClockFace() {
|
|
602
673
|
const isHour = this.activeSelection === 'hour';
|
|
603
674
|
let degrees = 0;
|
|
@@ -734,6 +805,30 @@ export class MoniTimePicker extends MoniElement {
|
|
|
734
805
|
`;
|
|
735
806
|
}
|
|
736
807
|
|
|
808
|
+
/**
|
|
809
|
+
* Renderiza el selector de hora (time picker) en modo `dial` o `input`.
|
|
810
|
+
*
|
|
811
|
+
* **Visualización 12 vs 24 horas:**
|
|
812
|
+
* `hourVal` convierte `currentHour` (0–23) al formato de visualización:
|
|
813
|
+
* - Modo 24 horas: string con ceros a la izquierda (ej. `'09'`, `'14'`).
|
|
814
|
+
* - Modo 12 horas: `0` → `12`, `13` → `1`, preservando la visualización AM/PM.
|
|
815
|
+
* `minuteVal` siempre tiene ceros a la izquierda para tener 2 dígitos.
|
|
816
|
+
*
|
|
817
|
+
* **Modo dial:**
|
|
818
|
+
* Renderiza una carátula de reloj DOM (HTML/CSS) con números distribuidos
|
|
819
|
+
* circularmente para cada hora/minuto. El sub-método `renderDialClockFace()`
|
|
820
|
+
* maneja la geometría y estilos que mueven la manecilla selectora mientras
|
|
821
|
+
* el usuario arrastra.
|
|
822
|
+
*
|
|
823
|
+
* **Modo input:**
|
|
824
|
+
* Renderiza dos elementos `<input type="number">` para la hora y el minuto con
|
|
825
|
+
* un selector AM/PM. El modo input es la alternativa (fallback) para accesibilidad
|
|
826
|
+
* y entornos no táctiles.
|
|
827
|
+
*
|
|
828
|
+
* **Alternador de modo:**
|
|
829
|
+
* Un icono de teclado cambia de modo `dial` a `input`; un icono de reloj
|
|
830
|
+
* cambia de vuelta.
|
|
831
|
+
*/
|
|
737
832
|
override render() {
|
|
738
833
|
const hourVal = !this.use24Hour
|
|
739
834
|
? String(this.currentHour > 12 ? this.currentHour - 12 : this.currentHour === 0 ? 12 : this.currentHour).padStart(2, '0')
|
|
@@ -14,27 +14,27 @@ describe('moni-toolbar (P5.4 — recreated)', () => {
|
|
|
14
14
|
el.remove();
|
|
15
15
|
});
|
|
16
16
|
|
|
17
|
-
it('
|
|
17
|
+
it('type=standard por defecto', async () => {
|
|
18
18
|
await el.updateComplete;
|
|
19
19
|
expect(el.type).toBe('standard');
|
|
20
20
|
expect(el.getAttribute('type')).toBe('standard');
|
|
21
21
|
});
|
|
22
22
|
|
|
23
|
-
it('
|
|
23
|
+
it('renderiza un contenedor <header>', async () => {
|
|
24
24
|
await el.updateComplete;
|
|
25
25
|
const header = el.shadowRoot?.querySelector('header');
|
|
26
26
|
expect(header).toBeTruthy();
|
|
27
27
|
expect(header?.getAttribute('part')).toBe('container');
|
|
28
28
|
});
|
|
29
29
|
|
|
30
|
-
it('
|
|
30
|
+
it('renderiza el atributo title en el span de título', async () => {
|
|
31
31
|
el.title = 'My App';
|
|
32
32
|
await el.updateComplete;
|
|
33
33
|
const title = el.shadowRoot?.querySelector('[part="title"]');
|
|
34
34
|
expect(title?.textContent?.trim()).toBe('My App');
|
|
35
35
|
});
|
|
36
36
|
|
|
37
|
-
it('
|
|
37
|
+
it('soporta slot de respaldo (fallback) cuando el atributo title está vacío', async () => {
|
|
38
38
|
const heading = document.createElement('h1');
|
|
39
39
|
heading.textContent = 'Slotted Title';
|
|
40
40
|
el.appendChild(heading);
|
|
@@ -46,7 +46,7 @@ describe('moni-toolbar (P5.4 — recreated)', () => {
|
|
|
46
46
|
expect(text).toBe('Slotted Title');
|
|
47
47
|
});
|
|
48
48
|
|
|
49
|
-
it('
|
|
49
|
+
it('renderiza los slots leading y trailing', async () => {
|
|
50
50
|
const leading = document.createElement('button');
|
|
51
51
|
leading.setAttribute('slot', 'leading');
|
|
52
52
|
leading.textContent = 'Menu';
|
|
@@ -66,7 +66,7 @@ describe('moni-toolbar (P5.4 — recreated)', () => {
|
|
|
66
66
|
expect(trailingSlot?.assignedNodes({ flatten: true }).length).toBeGreaterThan(0);
|
|
67
67
|
});
|
|
68
68
|
|
|
69
|
-
it('
|
|
69
|
+
it('cambia al tipo floating', async () => {
|
|
70
70
|
el.type = 'floating';
|
|
71
71
|
await el.updateComplete;
|
|
72
72
|
expect(el.getAttribute('type')).toBe('floating');
|
|
@@ -74,13 +74,13 @@ describe('moni-toolbar (P5.4 — recreated)', () => {
|
|
|
74
74
|
expect(header).toBeTruthy();
|
|
75
75
|
});
|
|
76
76
|
|
|
77
|
-
it('
|
|
77
|
+
it('refleja el atributo scroll', async () => {
|
|
78
78
|
el.scrolled = true;
|
|
79
79
|
await el.updateComplete;
|
|
80
80
|
expect(el.hasAttribute('scroll')).toBe(true);
|
|
81
81
|
});
|
|
82
82
|
|
|
83
|
-
it('
|
|
83
|
+
it('reserva un slot para el action-button', async () => {
|
|
84
84
|
const fab = document.createElement('button');
|
|
85
85
|
fab.setAttribute('slot', 'action-button');
|
|
86
86
|
fab.textContent = '+';
|