@lit-roa/cantidad 0.0.0-stage → 0.1.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/README.md +34 -2
- package/dist/cantidad.d.ts +37 -0
- package/dist/cantidad.d.ts.map +1 -0
- package/dist/cantidad.js +186 -0
- package/dist/cantidad.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/package.json +28 -4
- package/src/cantidad.ts +177 -0
- package/src/index.ts +1 -0
package/README.md
CHANGED
|
@@ -1,3 +1,35 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @lit-roa/cantidad
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Selector de cantidad con botones − y +. También se puede escribir el
|
|
4
|
+
número o usar las flechas ↑ ↓. Respeta `min` y `max` (por ejemplo, las
|
|
5
|
+
existencias) y funciona dentro de un `<form>` con `name`.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @lit-roa/cantidad
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
```html
|
|
12
|
+
<lr-cantidad valor="1" max="5"></lr-cantidad>
|
|
13
|
+
<script>
|
|
14
|
+
document.querySelector('lr-cantidad').addEventListener('cambio', (e) => console.log(e.detail.valor));
|
|
15
|
+
</script>
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
| Atributo | Tipo | Por omisión |
|
|
19
|
+
| --- | --- | --- |
|
|
20
|
+
| `valor` | `number` | `1` |
|
|
21
|
+
| `min` | `number` | `1` |
|
|
22
|
+
| `max` | `number` | sin límite |
|
|
23
|
+
| `paso` | `number` | `1` |
|
|
24
|
+
| `name` | `string` | `''` |
|
|
25
|
+
| `deshabilitado` | `boolean` | `false` |
|
|
26
|
+
| `tamano` | `chico` · `mediano` | `mediano` |
|
|
27
|
+
| `etiqueta` | `string` (texto accesible) | `'Cantidad'` |
|
|
28
|
+
|
|
29
|
+
Evento `cambio` con `{ valor }`. Estilo: `--lr-cantidad-borde`.
|
|
30
|
+
|
|
31
|
+
## Desarrollo
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm run dev -w @lit-roa/cantidad
|
|
35
|
+
```
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { LitElement } from 'lit';
|
|
2
|
+
export interface DetalleCambioCantidad {
|
|
3
|
+
valor: number;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Selector de cantidad con botones − y +. También se puede escribir el
|
|
7
|
+
* número. Participa en formularios con `name`.
|
|
8
|
+
*
|
|
9
|
+
* @fires cambio - Cuando cambia la cantidad. `detail`: `{ valor }`.
|
|
10
|
+
*/
|
|
11
|
+
export declare class LrCantidad extends LitElement {
|
|
12
|
+
static formAssociated: boolean;
|
|
13
|
+
static styles: import("lit").CSSResult[];
|
|
14
|
+
valor: number;
|
|
15
|
+
min: number;
|
|
16
|
+
/** Máximo (por ejemplo, las existencias). Sin límite si no se indica. */
|
|
17
|
+
max?: number;
|
|
18
|
+
paso: number;
|
|
19
|
+
name: string;
|
|
20
|
+
deshabilitado: boolean;
|
|
21
|
+
tamano: 'chico' | 'mediano';
|
|
22
|
+
/** Texto accesible del campo. */
|
|
23
|
+
etiqueta: string;
|
|
24
|
+
private internos;
|
|
25
|
+
render(): import("lit-html").TemplateResult<1>;
|
|
26
|
+
protected updated(): void;
|
|
27
|
+
private limitar;
|
|
28
|
+
private fijar;
|
|
29
|
+
private alEscribir;
|
|
30
|
+
private alTeclear;
|
|
31
|
+
}
|
|
32
|
+
declare global {
|
|
33
|
+
interface HTMLElementTagNameMap {
|
|
34
|
+
'lr-cantidad': LrCantidad;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=cantidad.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cantidad.d.ts","sourceRoot":"","sources":["../src/cantidad.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAa,MAAM,KAAK,CAAC;AAI5C,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;GAKG;AACH,qBACa,UAAW,SAAQ,UAAU;IACxC,MAAM,CAAC,cAAc,UAAQ;IAE7B,OAAgB,MAAM,4BA+DpB;IAE0B,KAAK,SAAK;IAEV,GAAG,SAAK;IAEpC,yEAAyE;IAC7C,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb,IAAI,SAAK;IAEzB,IAAI,SAAM;IAEsB,aAAa,UAAS;IAErC,MAAM,EAAE,OAAO,GAAG,SAAS,CAAa;IAErE,iCAAiC;IACrB,QAAQ,SAAc;IAElC,OAAO,CAAC,QAAQ,CAA0B;IAEjC,MAAM;cAmCI,OAAO;IAI1B,OAAO,CAAC,OAAO;IAMf,OAAO,CAAC,KAAK;IAUb,OAAO,CAAC,UAAU;IAMlB,OAAO,CAAC,SAAS;CAMlB;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,aAAa,EAAE,UAAU,CAAC;KAC3B;CACF"}
|
package/dist/cantidad.js
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { LitElement, css, html } from 'lit';
|
|
8
|
+
import { customElement, property } from 'lit/decorators.js';
|
|
9
|
+
import { emitir, estilosBase, iconoMinus, iconoPlus, tokens } from '@lit-roa/base';
|
|
10
|
+
/**
|
|
11
|
+
* Selector de cantidad con botones − y +. También se puede escribir el
|
|
12
|
+
* número. Participa en formularios con `name`.
|
|
13
|
+
*
|
|
14
|
+
* @fires cambio - Cuando cambia la cantidad. `detail`: `{ valor }`.
|
|
15
|
+
*/
|
|
16
|
+
let LrCantidad = class LrCantidad extends LitElement {
|
|
17
|
+
constructor() {
|
|
18
|
+
super(...arguments);
|
|
19
|
+
this.valor = 1;
|
|
20
|
+
this.min = 1;
|
|
21
|
+
this.paso = 1;
|
|
22
|
+
this.name = '';
|
|
23
|
+
this.deshabilitado = false;
|
|
24
|
+
this.tamano = 'mediano';
|
|
25
|
+
/** Texto accesible del campo. */
|
|
26
|
+
this.etiqueta = 'Cantidad';
|
|
27
|
+
this.internos = this.attachInternals();
|
|
28
|
+
}
|
|
29
|
+
static { this.formAssociated = true; }
|
|
30
|
+
static { this.styles = [
|
|
31
|
+
tokens,
|
|
32
|
+
estilosBase,
|
|
33
|
+
css `
|
|
34
|
+
:host {
|
|
35
|
+
display: inline-flex;
|
|
36
|
+
--_alto: 2.5rem;
|
|
37
|
+
}
|
|
38
|
+
:host([tamano='chico']) {
|
|
39
|
+
--_alto: 2rem;
|
|
40
|
+
}
|
|
41
|
+
.caja {
|
|
42
|
+
display: inline-flex;
|
|
43
|
+
align-items: stretch;
|
|
44
|
+
height: var(--_alto);
|
|
45
|
+
border: 1.5px solid var(--lr-cantidad-borde, #d1d5db);
|
|
46
|
+
border-radius: calc(var(--_radio) / 1.5);
|
|
47
|
+
background: var(--_color-fondo);
|
|
48
|
+
overflow: hidden;
|
|
49
|
+
}
|
|
50
|
+
.caja:focus-within {
|
|
51
|
+
border-color: var(--_color-primario);
|
|
52
|
+
}
|
|
53
|
+
button {
|
|
54
|
+
all: unset;
|
|
55
|
+
display: grid;
|
|
56
|
+
place-items: center;
|
|
57
|
+
width: var(--_alto);
|
|
58
|
+
font-size: 1rem;
|
|
59
|
+
color: var(--_color-texto);
|
|
60
|
+
cursor: pointer;
|
|
61
|
+
}
|
|
62
|
+
button:hover:not(:disabled) {
|
|
63
|
+
background: #f3f4f6;
|
|
64
|
+
}
|
|
65
|
+
button:disabled {
|
|
66
|
+
color: #d1d5db;
|
|
67
|
+
cursor: not-allowed;
|
|
68
|
+
}
|
|
69
|
+
button:focus-visible {
|
|
70
|
+
outline: 2px solid var(--_color-primario);
|
|
71
|
+
outline-offset: -2px;
|
|
72
|
+
}
|
|
73
|
+
input {
|
|
74
|
+
width: 2.75rem;
|
|
75
|
+
border: 0;
|
|
76
|
+
outline: 0;
|
|
77
|
+
background: transparent;
|
|
78
|
+
color: inherit;
|
|
79
|
+
font: inherit;
|
|
80
|
+
font-weight: 600;
|
|
81
|
+
text-align: center;
|
|
82
|
+
-moz-appearance: textfield;
|
|
83
|
+
}
|
|
84
|
+
input::-webkit-inner-spin-button,
|
|
85
|
+
input::-webkit-outer-spin-button {
|
|
86
|
+
-webkit-appearance: none;
|
|
87
|
+
margin: 0;
|
|
88
|
+
}
|
|
89
|
+
:host([deshabilitado]) .caja {
|
|
90
|
+
opacity: 0.55;
|
|
91
|
+
}
|
|
92
|
+
`,
|
|
93
|
+
]; }
|
|
94
|
+
render() {
|
|
95
|
+
const enMinimo = this.valor <= this.min;
|
|
96
|
+
const enMaximo = this.max !== undefined && this.valor >= this.max;
|
|
97
|
+
return html `<div class="caja" role="group" aria-label=${this.etiqueta}>
|
|
98
|
+
<button
|
|
99
|
+
type="button"
|
|
100
|
+
aria-label="Quitar uno"
|
|
101
|
+
?disabled=${this.deshabilitado || enMinimo}
|
|
102
|
+
@click=${() => this.fijar(this.valor - this.paso)}
|
|
103
|
+
>
|
|
104
|
+
${iconoMinus}
|
|
105
|
+
</button>
|
|
106
|
+
<input
|
|
107
|
+
type="number"
|
|
108
|
+
inputmode="numeric"
|
|
109
|
+
aria-label=${this.etiqueta}
|
|
110
|
+
.value=${String(this.valor)}
|
|
111
|
+
min=${this.min}
|
|
112
|
+
max=${this.max ?? ''}
|
|
113
|
+
step=${this.paso}
|
|
114
|
+
?disabled=${this.deshabilitado}
|
|
115
|
+
@change=${this.alEscribir}
|
|
116
|
+
@keydown=${this.alTeclear}
|
|
117
|
+
/>
|
|
118
|
+
<button
|
|
119
|
+
type="button"
|
|
120
|
+
aria-label="Agregar uno"
|
|
121
|
+
?disabled=${this.deshabilitado || enMaximo}
|
|
122
|
+
@click=${() => this.fijar(this.valor + this.paso)}
|
|
123
|
+
>
|
|
124
|
+
${iconoPlus}
|
|
125
|
+
</button>
|
|
126
|
+
</div>`;
|
|
127
|
+
}
|
|
128
|
+
updated() {
|
|
129
|
+
this.internos.setFormValue(String(this.valor));
|
|
130
|
+
}
|
|
131
|
+
limitar(n) {
|
|
132
|
+
if (Number.isNaN(n))
|
|
133
|
+
return this.min;
|
|
134
|
+
const conMax = this.max !== undefined ? Math.min(this.max, n) : n;
|
|
135
|
+
return Math.max(this.min, Math.round(conMax));
|
|
136
|
+
}
|
|
137
|
+
fijar(n) {
|
|
138
|
+
const valor = this.limitar(n);
|
|
139
|
+
if (valor === this.valor) {
|
|
140
|
+
this.requestUpdate(); // regresa el input al valor válido
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
this.valor = valor;
|
|
144
|
+
emitir(this, 'cambio', { valor });
|
|
145
|
+
}
|
|
146
|
+
alEscribir(evento) {
|
|
147
|
+
const input = evento.target;
|
|
148
|
+
this.fijar(Number(input.value));
|
|
149
|
+
input.value = String(this.valor);
|
|
150
|
+
}
|
|
151
|
+
alTeclear(evento) {
|
|
152
|
+
if (evento.key === 'ArrowUp' || evento.key === 'ArrowDown') {
|
|
153
|
+
evento.preventDefault();
|
|
154
|
+
this.fijar(this.valor + (evento.key === 'ArrowUp' ? this.paso : -this.paso));
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
__decorate([
|
|
159
|
+
property({ type: Number })
|
|
160
|
+
], LrCantidad.prototype, "valor", void 0);
|
|
161
|
+
__decorate([
|
|
162
|
+
property({ type: Number })
|
|
163
|
+
], LrCantidad.prototype, "min", void 0);
|
|
164
|
+
__decorate([
|
|
165
|
+
property({ type: Number })
|
|
166
|
+
], LrCantidad.prototype, "max", void 0);
|
|
167
|
+
__decorate([
|
|
168
|
+
property({ type: Number })
|
|
169
|
+
], LrCantidad.prototype, "paso", void 0);
|
|
170
|
+
__decorate([
|
|
171
|
+
property()
|
|
172
|
+
], LrCantidad.prototype, "name", void 0);
|
|
173
|
+
__decorate([
|
|
174
|
+
property({ type: Boolean, reflect: true })
|
|
175
|
+
], LrCantidad.prototype, "deshabilitado", void 0);
|
|
176
|
+
__decorate([
|
|
177
|
+
property({ reflect: true })
|
|
178
|
+
], LrCantidad.prototype, "tamano", void 0);
|
|
179
|
+
__decorate([
|
|
180
|
+
property()
|
|
181
|
+
], LrCantidad.prototype, "etiqueta", void 0);
|
|
182
|
+
LrCantidad = __decorate([
|
|
183
|
+
customElement('lr-cantidad')
|
|
184
|
+
], LrCantidad);
|
|
185
|
+
export { LrCantidad };
|
|
186
|
+
//# sourceMappingURL=cantidad.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cantidad.js","sourceRoot":"","sources":["../src/cantidad.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,qBAAqB,EAAE,MAAM,eAAe,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAA8B,MAAM,eAAe,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,30 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lit-roa/cantidad",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"description": "Selector de cantidad con botones − y +.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"default": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"src"
|
|
17
|
+
],
|
|
18
|
+
"sideEffects": [
|
|
19
|
+
"./dist/index.js"
|
|
20
|
+
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"dev": "vite",
|
|
23
|
+
"build": "tsc -b"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@lit-roa/base": "^0.5.0",
|
|
27
|
+
"lit": "^3.3.3"
|
|
28
|
+
},
|
|
29
|
+
"license": "MIT"
|
|
30
|
+
}
|
package/src/cantidad.ts
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { LitElement, css, html } from 'lit';
|
|
2
|
+
import { customElement, property } from 'lit/decorators.js';
|
|
3
|
+
import { emitir, estilosBase, iconoMinus, iconoPlus, tokens } from '@lit-roa/base';
|
|
4
|
+
|
|
5
|
+
export interface DetalleCambioCantidad {
|
|
6
|
+
valor: number;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Selector de cantidad con botones − y +. También se puede escribir el
|
|
11
|
+
* número. Participa en formularios con `name`.
|
|
12
|
+
*
|
|
13
|
+
* @fires cambio - Cuando cambia la cantidad. `detail`: `{ valor }`.
|
|
14
|
+
*/
|
|
15
|
+
@customElement('lr-cantidad')
|
|
16
|
+
export class LrCantidad extends LitElement {
|
|
17
|
+
static formAssociated = true;
|
|
18
|
+
|
|
19
|
+
static override styles = [
|
|
20
|
+
tokens,
|
|
21
|
+
estilosBase,
|
|
22
|
+
css`
|
|
23
|
+
:host {
|
|
24
|
+
display: inline-flex;
|
|
25
|
+
--_alto: 2.5rem;
|
|
26
|
+
}
|
|
27
|
+
:host([tamano='chico']) {
|
|
28
|
+
--_alto: 2rem;
|
|
29
|
+
}
|
|
30
|
+
.caja {
|
|
31
|
+
display: inline-flex;
|
|
32
|
+
align-items: stretch;
|
|
33
|
+
height: var(--_alto);
|
|
34
|
+
border: 1.5px solid var(--lr-cantidad-borde, #d1d5db);
|
|
35
|
+
border-radius: calc(var(--_radio) / 1.5);
|
|
36
|
+
background: var(--_color-fondo);
|
|
37
|
+
overflow: hidden;
|
|
38
|
+
}
|
|
39
|
+
.caja:focus-within {
|
|
40
|
+
border-color: var(--_color-primario);
|
|
41
|
+
}
|
|
42
|
+
button {
|
|
43
|
+
all: unset;
|
|
44
|
+
display: grid;
|
|
45
|
+
place-items: center;
|
|
46
|
+
width: var(--_alto);
|
|
47
|
+
font-size: 1rem;
|
|
48
|
+
color: var(--_color-texto);
|
|
49
|
+
cursor: pointer;
|
|
50
|
+
}
|
|
51
|
+
button:hover:not(:disabled) {
|
|
52
|
+
background: #f3f4f6;
|
|
53
|
+
}
|
|
54
|
+
button:disabled {
|
|
55
|
+
color: #d1d5db;
|
|
56
|
+
cursor: not-allowed;
|
|
57
|
+
}
|
|
58
|
+
button:focus-visible {
|
|
59
|
+
outline: 2px solid var(--_color-primario);
|
|
60
|
+
outline-offset: -2px;
|
|
61
|
+
}
|
|
62
|
+
input {
|
|
63
|
+
width: 2.75rem;
|
|
64
|
+
border: 0;
|
|
65
|
+
outline: 0;
|
|
66
|
+
background: transparent;
|
|
67
|
+
color: inherit;
|
|
68
|
+
font: inherit;
|
|
69
|
+
font-weight: 600;
|
|
70
|
+
text-align: center;
|
|
71
|
+
-moz-appearance: textfield;
|
|
72
|
+
}
|
|
73
|
+
input::-webkit-inner-spin-button,
|
|
74
|
+
input::-webkit-outer-spin-button {
|
|
75
|
+
-webkit-appearance: none;
|
|
76
|
+
margin: 0;
|
|
77
|
+
}
|
|
78
|
+
:host([deshabilitado]) .caja {
|
|
79
|
+
opacity: 0.55;
|
|
80
|
+
}
|
|
81
|
+
`,
|
|
82
|
+
];
|
|
83
|
+
|
|
84
|
+
@property({ type: Number }) valor = 1;
|
|
85
|
+
|
|
86
|
+
@property({ type: Number }) min = 1;
|
|
87
|
+
|
|
88
|
+
/** Máximo (por ejemplo, las existencias). Sin límite si no se indica. */
|
|
89
|
+
@property({ type: Number }) max?: number;
|
|
90
|
+
|
|
91
|
+
@property({ type: Number }) paso = 1;
|
|
92
|
+
|
|
93
|
+
@property() name = '';
|
|
94
|
+
|
|
95
|
+
@property({ type: Boolean, reflect: true }) deshabilitado = false;
|
|
96
|
+
|
|
97
|
+
@property({ reflect: true }) tamano: 'chico' | 'mediano' = 'mediano';
|
|
98
|
+
|
|
99
|
+
/** Texto accesible del campo. */
|
|
100
|
+
@property() etiqueta = 'Cantidad';
|
|
101
|
+
|
|
102
|
+
private internos = this.attachInternals();
|
|
103
|
+
|
|
104
|
+
override render() {
|
|
105
|
+
const enMinimo = this.valor <= this.min;
|
|
106
|
+
const enMaximo = this.max !== undefined && this.valor >= this.max;
|
|
107
|
+
return html`<div class="caja" role="group" aria-label=${this.etiqueta}>
|
|
108
|
+
<button
|
|
109
|
+
type="button"
|
|
110
|
+
aria-label="Quitar uno"
|
|
111
|
+
?disabled=${this.deshabilitado || enMinimo}
|
|
112
|
+
@click=${() => this.fijar(this.valor - this.paso)}
|
|
113
|
+
>
|
|
114
|
+
${iconoMinus}
|
|
115
|
+
</button>
|
|
116
|
+
<input
|
|
117
|
+
type="number"
|
|
118
|
+
inputmode="numeric"
|
|
119
|
+
aria-label=${this.etiqueta}
|
|
120
|
+
.value=${String(this.valor)}
|
|
121
|
+
min=${this.min}
|
|
122
|
+
max=${this.max ?? ''}
|
|
123
|
+
step=${this.paso}
|
|
124
|
+
?disabled=${this.deshabilitado}
|
|
125
|
+
@change=${this.alEscribir}
|
|
126
|
+
@keydown=${this.alTeclear}
|
|
127
|
+
/>
|
|
128
|
+
<button
|
|
129
|
+
type="button"
|
|
130
|
+
aria-label="Agregar uno"
|
|
131
|
+
?disabled=${this.deshabilitado || enMaximo}
|
|
132
|
+
@click=${() => this.fijar(this.valor + this.paso)}
|
|
133
|
+
>
|
|
134
|
+
${iconoPlus}
|
|
135
|
+
</button>
|
|
136
|
+
</div>`;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
protected override updated() {
|
|
140
|
+
this.internos.setFormValue(String(this.valor));
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
private limitar(n: number) {
|
|
144
|
+
if (Number.isNaN(n)) return this.min;
|
|
145
|
+
const conMax = this.max !== undefined ? Math.min(this.max, n) : n;
|
|
146
|
+
return Math.max(this.min, Math.round(conMax));
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
private fijar(n: number) {
|
|
150
|
+
const valor = this.limitar(n);
|
|
151
|
+
if (valor === this.valor) {
|
|
152
|
+
this.requestUpdate(); // regresa el input al valor válido
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
this.valor = valor;
|
|
156
|
+
emitir<DetalleCambioCantidad>(this, 'cambio', { valor });
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
private alEscribir(evento: Event) {
|
|
160
|
+
const input = evento.target as HTMLInputElement;
|
|
161
|
+
this.fijar(Number(input.value));
|
|
162
|
+
input.value = String(this.valor);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
private alTeclear(evento: KeyboardEvent) {
|
|
166
|
+
if (evento.key === 'ArrowUp' || evento.key === 'ArrowDown') {
|
|
167
|
+
evento.preventDefault();
|
|
168
|
+
this.fijar(this.valor + (evento.key === 'ArrowUp' ? this.paso : -this.paso));
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
declare global {
|
|
174
|
+
interface HTMLElementTagNameMap {
|
|
175
|
+
'lr-cantidad': LrCantidad;
|
|
176
|
+
}
|
|
177
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { LrCantidad, type DetalleCambioCantidad } from './cantidad.js';
|