@lit-roa/pasos 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 +33 -2
- 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/dist/pasos.d.ts +34 -0
- package/dist/pasos.d.ts.map +1 -0
- package/dist/pasos.js +227 -0
- package/dist/pasos.js.map +1 -0
- package/package.json +31 -4
- package/src/index.ts +1 -0
- package/src/pasos.ts +227 -0
package/README.md
CHANGED
|
@@ -1,3 +1,34 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @lit-roa/pasos
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Pasos del checkout (stepper). Los pasos ya hechos llevan palomita y se
|
|
4
|
+
pueden tocar para regresar. Si el componente mide menos de 520 px, muestra
|
|
5
|
+
"Envío · Paso 3 de 4" con barra de avance y una liga al paso anterior.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @lit-roa/pasos
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
```html
|
|
12
|
+
<lr-pasos actual="1" pasos='["Carrito","Datos","Envío","Pago"]'></lr-pasos>
|
|
13
|
+
<script>
|
|
14
|
+
const pasos = document.querySelector('lr-pasos');
|
|
15
|
+
pasos.addEventListener('cambio-paso', (e) => (pasos.actual = e.detail.indice));
|
|
16
|
+
</script>
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
El componente no cambia `actual` por su cuenta: avisa con `cambio-paso` y
|
|
20
|
+
tu sitio decide (por ejemplo, si los datos del paso actual son válidos).
|
|
21
|
+
|
|
22
|
+
| Atributo | Tipo | Por omisión |
|
|
23
|
+
| --- | --- | --- |
|
|
24
|
+
| `pasos` | `(string \| { titulo, descripcion? })[]` (JSON en atributo) | `[]` |
|
|
25
|
+
| `actual` | `number` (desde 0) | `0` |
|
|
26
|
+
| `sin-regresar` | `boolean` | `false` |
|
|
27
|
+
|
|
28
|
+
Evento `cambio-paso` con `{ indice, paso }`.
|
|
29
|
+
|
|
30
|
+
## Desarrollo
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
npm run dev -w @lit-roa/pasos
|
|
34
|
+
```
|
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,OAAO,EAAE,KAAK,iBAAiB,EAAE,KAAK,IAAI,EAAE,MAAM,YAAY,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,OAAO,EAAqC,MAAM,YAAY,CAAC"}
|
package/dist/pasos.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { LitElement } from 'lit';
|
|
2
|
+
export interface Paso {
|
|
3
|
+
titulo: string;
|
|
4
|
+
descripcion?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface DetalleCambioPaso {
|
|
7
|
+
indice: number;
|
|
8
|
+
paso: Paso;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Pasos del checkout (stepper). Los pasos anteriores al actual quedan
|
|
12
|
+
* marcados y se pueden tocar para regresar. En pantallas angostas muestra
|
|
13
|
+
* "Paso 2 de 4" con una barra de avance.
|
|
14
|
+
*
|
|
15
|
+
* @fires cambio-paso - Al tocar un paso ya hecho. `detail`: `{ indice, paso }`.
|
|
16
|
+
* El componente no cambia `actual`: lo hace el sitio.
|
|
17
|
+
*/
|
|
18
|
+
export declare class LrPasos extends LitElement {
|
|
19
|
+
static styles: import("lit").CSSResult[];
|
|
20
|
+
/** Pasos: textos o `{ titulo, descripcion }`. Como atributo, en JSON. */
|
|
21
|
+
pasos: (Paso | string)[];
|
|
22
|
+
/** Índice del paso actual, desde 0. */
|
|
23
|
+
actual: number;
|
|
24
|
+
/** Los pasos hechos no se pueden tocar. */
|
|
25
|
+
sinRegresar: boolean;
|
|
26
|
+
render(): import("lit-html").TemplateResult<1>;
|
|
27
|
+
private elegir;
|
|
28
|
+
}
|
|
29
|
+
declare global {
|
|
30
|
+
interface HTMLElementTagNameMap {
|
|
31
|
+
'lr-pasos': LrPasos;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=pasos.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pasos.d.ts","sourceRoot":"","sources":["../src/pasos.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAsB,MAAM,KAAK,CAAC;AAIrD,MAAM,WAAW,IAAI;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,IAAI,CAAC;CACZ;AAED;;;;;;;GAOG;AACH,qBACa,OAAQ,SAAQ,UAAU;IACrC,OAAgB,MAAM,4BAiJpB;IAEF,yEAAyE;IAC9C,KAAK,EAAE,CAAC,IAAI,GAAG,MAAM,CAAC,EAAE,CAAM;IAEzD,uCAAuC;IACX,MAAM,SAAK;IAEvC,2CAA2C;IACa,WAAW,UAAS;IAEnE,MAAM;IAqCf,OAAO,CAAC,MAAM;CAGf;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,UAAU,EAAE,OAAO,CAAC;KACrB;CACF"}
|
package/dist/pasos.js
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
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, nothing } from 'lit';
|
|
8
|
+
import { customElement, property } from 'lit/decorators.js';
|
|
9
|
+
import { emitir, estilosBase, iconoCheck, tokens } from '@lit-roa/base';
|
|
10
|
+
/**
|
|
11
|
+
* Pasos del checkout (stepper). Los pasos anteriores al actual quedan
|
|
12
|
+
* marcados y se pueden tocar para regresar. En pantallas angostas muestra
|
|
13
|
+
* "Paso 2 de 4" con una barra de avance.
|
|
14
|
+
*
|
|
15
|
+
* @fires cambio-paso - Al tocar un paso ya hecho. `detail`: `{ indice, paso }`.
|
|
16
|
+
* El componente no cambia `actual`: lo hace el sitio.
|
|
17
|
+
*/
|
|
18
|
+
let LrPasos = class LrPasos extends LitElement {
|
|
19
|
+
constructor() {
|
|
20
|
+
super(...arguments);
|
|
21
|
+
/** Pasos: textos o `{ titulo, descripcion }`. Como atributo, en JSON. */
|
|
22
|
+
this.pasos = [];
|
|
23
|
+
/** Índice del paso actual, desde 0. */
|
|
24
|
+
this.actual = 0;
|
|
25
|
+
/** Los pasos hechos no se pueden tocar. */
|
|
26
|
+
this.sinRegresar = false;
|
|
27
|
+
}
|
|
28
|
+
static { this.styles = [
|
|
29
|
+
tokens,
|
|
30
|
+
estilosBase,
|
|
31
|
+
css `
|
|
32
|
+
:host {
|
|
33
|
+
display: block;
|
|
34
|
+
container-type: inline-size;
|
|
35
|
+
}
|
|
36
|
+
ol {
|
|
37
|
+
display: flex;
|
|
38
|
+
margin: 0;
|
|
39
|
+
padding: 0;
|
|
40
|
+
list-style: none;
|
|
41
|
+
}
|
|
42
|
+
li {
|
|
43
|
+
flex: 1;
|
|
44
|
+
position: relative;
|
|
45
|
+
display: flex;
|
|
46
|
+
flex-direction: column;
|
|
47
|
+
align-items: center;
|
|
48
|
+
text-align: center;
|
|
49
|
+
min-width: 0;
|
|
50
|
+
}
|
|
51
|
+
li:not(:first-child)::before {
|
|
52
|
+
content: '';
|
|
53
|
+
position: absolute;
|
|
54
|
+
top: 1rem;
|
|
55
|
+
right: calc(50% + 1.25rem);
|
|
56
|
+
left: calc(-50% + 1.25rem);
|
|
57
|
+
height: 2px;
|
|
58
|
+
background: var(--_color-borde);
|
|
59
|
+
}
|
|
60
|
+
li.hecho::before,
|
|
61
|
+
li.actual::before {
|
|
62
|
+
background: var(--_color-primario);
|
|
63
|
+
}
|
|
64
|
+
.marca {
|
|
65
|
+
all: unset;
|
|
66
|
+
box-sizing: border-box;
|
|
67
|
+
display: flex;
|
|
68
|
+
flex-direction: column;
|
|
69
|
+
align-items: center;
|
|
70
|
+
gap: 0.5rem;
|
|
71
|
+
max-width: 100%;
|
|
72
|
+
}
|
|
73
|
+
button.marca {
|
|
74
|
+
cursor: pointer;
|
|
75
|
+
}
|
|
76
|
+
button.marca:hover .titulo {
|
|
77
|
+
text-decoration: underline;
|
|
78
|
+
}
|
|
79
|
+
button.marca:focus-visible .circulo {
|
|
80
|
+
outline: 2px solid var(--_color-primario);
|
|
81
|
+
outline-offset: 2px;
|
|
82
|
+
}
|
|
83
|
+
.circulo {
|
|
84
|
+
display: grid;
|
|
85
|
+
place-items: center;
|
|
86
|
+
width: 2rem;
|
|
87
|
+
height: 2rem;
|
|
88
|
+
border-radius: 999px;
|
|
89
|
+
border: 2px solid var(--_color-borde);
|
|
90
|
+
background: var(--_color-fondo);
|
|
91
|
+
color: var(--_color-texto-suave);
|
|
92
|
+
font-size: 0.875rem;
|
|
93
|
+
font-weight: 700;
|
|
94
|
+
}
|
|
95
|
+
.hecho .circulo {
|
|
96
|
+
border-color: var(--_color-primario);
|
|
97
|
+
background: var(--_color-primario);
|
|
98
|
+
color: var(--_color-sobre-primario);
|
|
99
|
+
font-size: 1rem;
|
|
100
|
+
}
|
|
101
|
+
.actual .circulo {
|
|
102
|
+
border-color: var(--_color-primario);
|
|
103
|
+
color: var(--_color-primario);
|
|
104
|
+
box-shadow: 0 0 0 4px color-mix(in srgb, var(--_color-primario) 18%, transparent);
|
|
105
|
+
}
|
|
106
|
+
.titulo {
|
|
107
|
+
font-size: 0.875rem;
|
|
108
|
+
font-weight: 600;
|
|
109
|
+
color: var(--_color-texto-suave);
|
|
110
|
+
overflow: hidden;
|
|
111
|
+
text-overflow: ellipsis;
|
|
112
|
+
max-width: 100%;
|
|
113
|
+
}
|
|
114
|
+
.hecho .titulo,
|
|
115
|
+
.actual .titulo {
|
|
116
|
+
color: var(--_color-texto);
|
|
117
|
+
}
|
|
118
|
+
.descripcion {
|
|
119
|
+
font-size: 0.75rem;
|
|
120
|
+
color: var(--_color-texto-suave);
|
|
121
|
+
margin-top: -0.25rem;
|
|
122
|
+
}
|
|
123
|
+
.compacto {
|
|
124
|
+
display: none;
|
|
125
|
+
}
|
|
126
|
+
@container (max-width: 520px) {
|
|
127
|
+
ol {
|
|
128
|
+
display: none;
|
|
129
|
+
}
|
|
130
|
+
.compacto {
|
|
131
|
+
display: grid;
|
|
132
|
+
gap: 0.5rem;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
.compacto .arriba {
|
|
136
|
+
display: flex;
|
|
137
|
+
justify-content: space-between;
|
|
138
|
+
align-items: baseline;
|
|
139
|
+
gap: 1rem;
|
|
140
|
+
font-size: 0.875rem;
|
|
141
|
+
}
|
|
142
|
+
.compacto strong {
|
|
143
|
+
font-size: 1rem;
|
|
144
|
+
}
|
|
145
|
+
.compacto span {
|
|
146
|
+
color: var(--_color-texto-suave);
|
|
147
|
+
white-space: nowrap;
|
|
148
|
+
}
|
|
149
|
+
.barra {
|
|
150
|
+
height: 6px;
|
|
151
|
+
border-radius: 999px;
|
|
152
|
+
background: var(--_color-borde);
|
|
153
|
+
overflow: hidden;
|
|
154
|
+
}
|
|
155
|
+
.barra i {
|
|
156
|
+
display: block;
|
|
157
|
+
height: 100%;
|
|
158
|
+
border-radius: inherit;
|
|
159
|
+
background: var(--_color-primario);
|
|
160
|
+
transition: width 0.3s;
|
|
161
|
+
}
|
|
162
|
+
.regresar {
|
|
163
|
+
all: unset;
|
|
164
|
+
justify-self: start;
|
|
165
|
+
font-size: 0.8125rem;
|
|
166
|
+
color: var(--_color-primario);
|
|
167
|
+
cursor: pointer;
|
|
168
|
+
}
|
|
169
|
+
.regresar:focus-visible {
|
|
170
|
+
outline: 2px solid var(--_color-primario);
|
|
171
|
+
}
|
|
172
|
+
`,
|
|
173
|
+
]; }
|
|
174
|
+
render() {
|
|
175
|
+
const pasos = this.pasos.map((p) => (typeof p === 'string' ? { titulo: p } : p));
|
|
176
|
+
const actual = Math.min(Math.max(0, this.actual), pasos.length - 1);
|
|
177
|
+
const anterior = pasos[actual - 1];
|
|
178
|
+
return html `
|
|
179
|
+
<nav aria-label="Pasos de la compra">
|
|
180
|
+
<ol>
|
|
181
|
+
${pasos.map((p, i) => {
|
|
182
|
+
const estado = i < actual ? 'hecho' : i === actual ? 'actual' : 'pendiente';
|
|
183
|
+
const contenido = html `<span class="circulo">${estado === 'hecho' ? iconoCheck : i + 1}</span>
|
|
184
|
+
<span class="titulo">${p.titulo}</span>
|
|
185
|
+
${p.descripcion ? html `<span class="descripcion">${p.descripcion}</span>` : nothing}`;
|
|
186
|
+
return html `<li class=${estado} aria-current=${estado === 'actual' ? 'step' : nothing}>
|
|
187
|
+
${estado === 'hecho' && !this.sinRegresar
|
|
188
|
+
? html `<button class="marca" aria-label="${p.titulo} (hecho), regresar" @click=${() => this.elegir(i, p)}>
|
|
189
|
+
${contenido}
|
|
190
|
+
</button>`
|
|
191
|
+
: html `<span class="marca">${contenido}</span>`}
|
|
192
|
+
</li>`;
|
|
193
|
+
})}
|
|
194
|
+
</ol>
|
|
195
|
+
<div class="compacto">
|
|
196
|
+
<div class="arriba">
|
|
197
|
+
<strong>${pasos[actual]?.titulo ?? ''}</strong>
|
|
198
|
+
<span>Paso ${actual + 1} de ${pasos.length}</span>
|
|
199
|
+
</div>
|
|
200
|
+
<div class="barra"><i style="width: ${((actual + 1) / Math.max(1, pasos.length)) * 100}%"></i></div>
|
|
201
|
+
${anterior && !this.sinRegresar
|
|
202
|
+
? html `<button class="regresar" @click=${() => this.elegir(actual - 1, anterior)}>
|
|
203
|
+
← ${anterior.titulo}
|
|
204
|
+
</button>`
|
|
205
|
+
: nothing}
|
|
206
|
+
</div>
|
|
207
|
+
</nav>
|
|
208
|
+
`;
|
|
209
|
+
}
|
|
210
|
+
elegir(indice, paso) {
|
|
211
|
+
emitir(this, 'cambio-paso', { indice, paso });
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
__decorate([
|
|
215
|
+
property({ type: Array })
|
|
216
|
+
], LrPasos.prototype, "pasos", void 0);
|
|
217
|
+
__decorate([
|
|
218
|
+
property({ type: Number })
|
|
219
|
+
], LrPasos.prototype, "actual", void 0);
|
|
220
|
+
__decorate([
|
|
221
|
+
property({ type: Boolean, attribute: 'sin-regresar' })
|
|
222
|
+
], LrPasos.prototype, "sinRegresar", void 0);
|
|
223
|
+
LrPasos = __decorate([
|
|
224
|
+
customElement('lr-pasos')
|
|
225
|
+
], LrPasos);
|
|
226
|
+
export { LrPasos };
|
|
227
|
+
//# sourceMappingURL=pasos.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pasos.js","sourceRoot":"","sources":["../src/pasos.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAYxE;;;;;;;GAOG;AAEI,IAAM,OAAO,GAAb,MAAM,OAAQ,SAAQ,UAAU;IAAhC;;QAoJL,yEAAyE;QAC9C,UAAK,GAAsB,EAAE,CAAC;QAEzD,uCAAuC;QACX,WAAM,GAAG,CAAC,CAAC;QAEvC,2CAA2C;QACa,gBAAW,GAAG,KAAK,CAAC;IA0C9E,CAAC;aApMiB,WAAM,GAAG;QACvB,MAAM;QACN,WAAW;QACX,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA6IF;KACF,AAjJqB,CAiJpB;IAWO,MAAM;QACb,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACjF,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACpE,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACnC,OAAO,IAAI,CAAA;;;YAGH,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YACnB,MAAM,MAAM,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC;YAC5E,MAAM,SAAS,GAAG,IAAI,CAAA,yBAAyB,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;qCAC7D,CAAC,CAAC,MAAM;gBAC7B,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAA,6BAA6B,CAAC,CAAC,WAAW,SAAS,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;YACxF,OAAO,IAAI,CAAA,aAAa,MAAM,iBAAiB,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO;gBACjF,MAAM,KAAK,OAAO,IAAI,CAAC,IAAI,CAAC,WAAW;gBACvC,CAAC,CAAC,IAAI,CAAA,qCAAqC,CAAC,CAAC,MAAM,8BAA8B,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC;sBAClG,SAAS;4BACH;gBACZ,CAAC,CAAC,IAAI,CAAA,uBAAuB,SAAS,SAAS;kBAC7C,CAAC;QACT,CAAC,CAAC;;;;sBAIU,KAAK,CAAC,MAAM,CAAC,EAAE,MAAM,IAAI,EAAE;yBACxB,MAAM,GAAG,CAAC,OAAO,KAAK,CAAC,MAAM;;gDAEN,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,GAAG;YACpF,QAAQ,IAAI,CAAC,IAAI,CAAC,WAAW;YAC7B,CAAC,CAAC,IAAI,CAAA,mCAAmC,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,QAAQ,CAAC;oBACxE,QAAQ,CAAC,MAAM;wBACX;YACZ,CAAC,CAAC,OAAO;;;KAGhB,CAAC;IACJ,CAAC;IAEO,MAAM,CAAC,MAAc,EAAE,IAAU;QACvC,MAAM,CAAoB,IAAI,EAAE,aAAa,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IACnE,CAAC;;AA/C0B;IAA1B,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;sCAA+B;AAG7B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;uCAAY;AAGiB;IAAvD,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,CAAC;4CAAqB;AA3JjE,OAAO;IADnB,aAAa,CAAC,UAAU,CAAC;GACb,OAAO,CAqMnB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,33 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lit-roa/pasos",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"description": "Pasos del checkout (stepper) responsive.",
|
|
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
|
+
"devDependencies": {
|
|
31
|
+
"@lit-roa/boton": "^0.1.3"
|
|
32
|
+
}
|
|
33
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { LrPasos, type DetalleCambioPaso, type Paso } from './pasos.js';
|
package/src/pasos.ts
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import { LitElement, css, html, nothing } from 'lit';
|
|
2
|
+
import { customElement, property } from 'lit/decorators.js';
|
|
3
|
+
import { emitir, estilosBase, iconoCheck, tokens } from '@lit-roa/base';
|
|
4
|
+
|
|
5
|
+
export interface Paso {
|
|
6
|
+
titulo: string;
|
|
7
|
+
descripcion?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface DetalleCambioPaso {
|
|
11
|
+
indice: number;
|
|
12
|
+
paso: Paso;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Pasos del checkout (stepper). Los pasos anteriores al actual quedan
|
|
17
|
+
* marcados y se pueden tocar para regresar. En pantallas angostas muestra
|
|
18
|
+
* "Paso 2 de 4" con una barra de avance.
|
|
19
|
+
*
|
|
20
|
+
* @fires cambio-paso - Al tocar un paso ya hecho. `detail`: `{ indice, paso }`.
|
|
21
|
+
* El componente no cambia `actual`: lo hace el sitio.
|
|
22
|
+
*/
|
|
23
|
+
@customElement('lr-pasos')
|
|
24
|
+
export class LrPasos extends LitElement {
|
|
25
|
+
static override styles = [
|
|
26
|
+
tokens,
|
|
27
|
+
estilosBase,
|
|
28
|
+
css`
|
|
29
|
+
:host {
|
|
30
|
+
display: block;
|
|
31
|
+
container-type: inline-size;
|
|
32
|
+
}
|
|
33
|
+
ol {
|
|
34
|
+
display: flex;
|
|
35
|
+
margin: 0;
|
|
36
|
+
padding: 0;
|
|
37
|
+
list-style: none;
|
|
38
|
+
}
|
|
39
|
+
li {
|
|
40
|
+
flex: 1;
|
|
41
|
+
position: relative;
|
|
42
|
+
display: flex;
|
|
43
|
+
flex-direction: column;
|
|
44
|
+
align-items: center;
|
|
45
|
+
text-align: center;
|
|
46
|
+
min-width: 0;
|
|
47
|
+
}
|
|
48
|
+
li:not(:first-child)::before {
|
|
49
|
+
content: '';
|
|
50
|
+
position: absolute;
|
|
51
|
+
top: 1rem;
|
|
52
|
+
right: calc(50% + 1.25rem);
|
|
53
|
+
left: calc(-50% + 1.25rem);
|
|
54
|
+
height: 2px;
|
|
55
|
+
background: var(--_color-borde);
|
|
56
|
+
}
|
|
57
|
+
li.hecho::before,
|
|
58
|
+
li.actual::before {
|
|
59
|
+
background: var(--_color-primario);
|
|
60
|
+
}
|
|
61
|
+
.marca {
|
|
62
|
+
all: unset;
|
|
63
|
+
box-sizing: border-box;
|
|
64
|
+
display: flex;
|
|
65
|
+
flex-direction: column;
|
|
66
|
+
align-items: center;
|
|
67
|
+
gap: 0.5rem;
|
|
68
|
+
max-width: 100%;
|
|
69
|
+
}
|
|
70
|
+
button.marca {
|
|
71
|
+
cursor: pointer;
|
|
72
|
+
}
|
|
73
|
+
button.marca:hover .titulo {
|
|
74
|
+
text-decoration: underline;
|
|
75
|
+
}
|
|
76
|
+
button.marca:focus-visible .circulo {
|
|
77
|
+
outline: 2px solid var(--_color-primario);
|
|
78
|
+
outline-offset: 2px;
|
|
79
|
+
}
|
|
80
|
+
.circulo {
|
|
81
|
+
display: grid;
|
|
82
|
+
place-items: center;
|
|
83
|
+
width: 2rem;
|
|
84
|
+
height: 2rem;
|
|
85
|
+
border-radius: 999px;
|
|
86
|
+
border: 2px solid var(--_color-borde);
|
|
87
|
+
background: var(--_color-fondo);
|
|
88
|
+
color: var(--_color-texto-suave);
|
|
89
|
+
font-size: 0.875rem;
|
|
90
|
+
font-weight: 700;
|
|
91
|
+
}
|
|
92
|
+
.hecho .circulo {
|
|
93
|
+
border-color: var(--_color-primario);
|
|
94
|
+
background: var(--_color-primario);
|
|
95
|
+
color: var(--_color-sobre-primario);
|
|
96
|
+
font-size: 1rem;
|
|
97
|
+
}
|
|
98
|
+
.actual .circulo {
|
|
99
|
+
border-color: var(--_color-primario);
|
|
100
|
+
color: var(--_color-primario);
|
|
101
|
+
box-shadow: 0 0 0 4px color-mix(in srgb, var(--_color-primario) 18%, transparent);
|
|
102
|
+
}
|
|
103
|
+
.titulo {
|
|
104
|
+
font-size: 0.875rem;
|
|
105
|
+
font-weight: 600;
|
|
106
|
+
color: var(--_color-texto-suave);
|
|
107
|
+
overflow: hidden;
|
|
108
|
+
text-overflow: ellipsis;
|
|
109
|
+
max-width: 100%;
|
|
110
|
+
}
|
|
111
|
+
.hecho .titulo,
|
|
112
|
+
.actual .titulo {
|
|
113
|
+
color: var(--_color-texto);
|
|
114
|
+
}
|
|
115
|
+
.descripcion {
|
|
116
|
+
font-size: 0.75rem;
|
|
117
|
+
color: var(--_color-texto-suave);
|
|
118
|
+
margin-top: -0.25rem;
|
|
119
|
+
}
|
|
120
|
+
.compacto {
|
|
121
|
+
display: none;
|
|
122
|
+
}
|
|
123
|
+
@container (max-width: 520px) {
|
|
124
|
+
ol {
|
|
125
|
+
display: none;
|
|
126
|
+
}
|
|
127
|
+
.compacto {
|
|
128
|
+
display: grid;
|
|
129
|
+
gap: 0.5rem;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
.compacto .arriba {
|
|
133
|
+
display: flex;
|
|
134
|
+
justify-content: space-between;
|
|
135
|
+
align-items: baseline;
|
|
136
|
+
gap: 1rem;
|
|
137
|
+
font-size: 0.875rem;
|
|
138
|
+
}
|
|
139
|
+
.compacto strong {
|
|
140
|
+
font-size: 1rem;
|
|
141
|
+
}
|
|
142
|
+
.compacto span {
|
|
143
|
+
color: var(--_color-texto-suave);
|
|
144
|
+
white-space: nowrap;
|
|
145
|
+
}
|
|
146
|
+
.barra {
|
|
147
|
+
height: 6px;
|
|
148
|
+
border-radius: 999px;
|
|
149
|
+
background: var(--_color-borde);
|
|
150
|
+
overflow: hidden;
|
|
151
|
+
}
|
|
152
|
+
.barra i {
|
|
153
|
+
display: block;
|
|
154
|
+
height: 100%;
|
|
155
|
+
border-radius: inherit;
|
|
156
|
+
background: var(--_color-primario);
|
|
157
|
+
transition: width 0.3s;
|
|
158
|
+
}
|
|
159
|
+
.regresar {
|
|
160
|
+
all: unset;
|
|
161
|
+
justify-self: start;
|
|
162
|
+
font-size: 0.8125rem;
|
|
163
|
+
color: var(--_color-primario);
|
|
164
|
+
cursor: pointer;
|
|
165
|
+
}
|
|
166
|
+
.regresar:focus-visible {
|
|
167
|
+
outline: 2px solid var(--_color-primario);
|
|
168
|
+
}
|
|
169
|
+
`,
|
|
170
|
+
];
|
|
171
|
+
|
|
172
|
+
/** Pasos: textos o `{ titulo, descripcion }`. Como atributo, en JSON. */
|
|
173
|
+
@property({ type: Array }) pasos: (Paso | string)[] = [];
|
|
174
|
+
|
|
175
|
+
/** Índice del paso actual, desde 0. */
|
|
176
|
+
@property({ type: Number }) actual = 0;
|
|
177
|
+
|
|
178
|
+
/** Los pasos hechos no se pueden tocar. */
|
|
179
|
+
@property({ type: Boolean, attribute: 'sin-regresar' }) sinRegresar = false;
|
|
180
|
+
|
|
181
|
+
override render() {
|
|
182
|
+
const pasos = this.pasos.map((p) => (typeof p === 'string' ? { titulo: p } : p));
|
|
183
|
+
const actual = Math.min(Math.max(0, this.actual), pasos.length - 1);
|
|
184
|
+
const anterior = pasos[actual - 1];
|
|
185
|
+
return html`
|
|
186
|
+
<nav aria-label="Pasos de la compra">
|
|
187
|
+
<ol>
|
|
188
|
+
${pasos.map((p, i) => {
|
|
189
|
+
const estado = i < actual ? 'hecho' : i === actual ? 'actual' : 'pendiente';
|
|
190
|
+
const contenido = html`<span class="circulo">${estado === 'hecho' ? iconoCheck : i + 1}</span>
|
|
191
|
+
<span class="titulo">${p.titulo}</span>
|
|
192
|
+
${p.descripcion ? html`<span class="descripcion">${p.descripcion}</span>` : nothing}`;
|
|
193
|
+
return html`<li class=${estado} aria-current=${estado === 'actual' ? 'step' : nothing}>
|
|
194
|
+
${estado === 'hecho' && !this.sinRegresar
|
|
195
|
+
? html`<button class="marca" aria-label="${p.titulo} (hecho), regresar" @click=${() => this.elegir(i, p)}>
|
|
196
|
+
${contenido}
|
|
197
|
+
</button>`
|
|
198
|
+
: html`<span class="marca">${contenido}</span>`}
|
|
199
|
+
</li>`;
|
|
200
|
+
})}
|
|
201
|
+
</ol>
|
|
202
|
+
<div class="compacto">
|
|
203
|
+
<div class="arriba">
|
|
204
|
+
<strong>${pasos[actual]?.titulo ?? ''}</strong>
|
|
205
|
+
<span>Paso ${actual + 1} de ${pasos.length}</span>
|
|
206
|
+
</div>
|
|
207
|
+
<div class="barra"><i style="width: ${((actual + 1) / Math.max(1, pasos.length)) * 100}%"></i></div>
|
|
208
|
+
${anterior && !this.sinRegresar
|
|
209
|
+
? html`<button class="regresar" @click=${() => this.elegir(actual - 1, anterior)}>
|
|
210
|
+
← ${anterior.titulo}
|
|
211
|
+
</button>`
|
|
212
|
+
: nothing}
|
|
213
|
+
</div>
|
|
214
|
+
</nav>
|
|
215
|
+
`;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
private elegir(indice: number, paso: Paso) {
|
|
219
|
+
emitir<DetalleCambioPaso>(this, 'cambio-paso', { indice, paso });
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
declare global {
|
|
224
|
+
interface HTMLElementTagNameMap {
|
|
225
|
+
'lr-pasos': LrPasos;
|
|
226
|
+
}
|
|
227
|
+
}
|