upop 1.0.1
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/package.json +10 -0
- package/src/index.html +117 -0
- package/src/upop.css +124 -0
- package/src/upop.js +135 -0
package/package.json
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "upop",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "Pequeña librería de modales y toasters modernos en vanilla JS",
|
|
5
|
+
"main": "src/upop.js",
|
|
6
|
+
"style": "src/upop.css",
|
|
7
|
+
"keywords": ["alert", "toast", "modal", "notification", "vanilla-js"],
|
|
8
|
+
"author": "Luca",
|
|
9
|
+
"license": "MIT"
|
|
10
|
+
}
|
package/src/index.html
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="es">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<title>Demo UPOP</title>
|
|
6
|
+
<link rel="stylesheet" href="./upop.css">
|
|
7
|
+
<style>
|
|
8
|
+
body {
|
|
9
|
+
font-family: 'Geist', sans-serif;
|
|
10
|
+
padding: 40px;
|
|
11
|
+
background: #f5f5f5;
|
|
12
|
+
color: #333;
|
|
13
|
+
}
|
|
14
|
+
h1 { margin-bottom: 20px; }
|
|
15
|
+
.seccion { margin-bottom: 40px; }
|
|
16
|
+
button {
|
|
17
|
+
margin: 6px;
|
|
18
|
+
padding: 10px 16px;
|
|
19
|
+
border: none;
|
|
20
|
+
border-radius: 8px;
|
|
21
|
+
cursor: pointer;
|
|
22
|
+
font-size: 14px;
|
|
23
|
+
background: #0d6efd;
|
|
24
|
+
color: #fff;
|
|
25
|
+
transition: background .2s ease;
|
|
26
|
+
}
|
|
27
|
+
button:hover { background: #0b5ed7; }
|
|
28
|
+
</style>
|
|
29
|
+
</head>
|
|
30
|
+
<body>
|
|
31
|
+
<h1>Demo UPOP</h1>
|
|
32
|
+
|
|
33
|
+
<div class="seccion">
|
|
34
|
+
<h2>Alerts</h2>
|
|
35
|
+
<button id="alertInfo">Info</button>
|
|
36
|
+
<button id="alertSuccess">Éxito</button>
|
|
37
|
+
<button id="alertError">Error</button>
|
|
38
|
+
<button id="alertWarning">Advertencia</button>
|
|
39
|
+
</div>
|
|
40
|
+
|
|
41
|
+
<div class="seccion">
|
|
42
|
+
<h2>Toasts</h2>
|
|
43
|
+
<button id="toastInfo">Info</button>
|
|
44
|
+
<button id="toastSuccess">Éxito</button>
|
|
45
|
+
<button id="toastError">Error</button>
|
|
46
|
+
<button id="toastWarning">Advertencia</button>
|
|
47
|
+
</div>
|
|
48
|
+
|
|
49
|
+
<div class="seccion">
|
|
50
|
+
<h2>Confirms</h2>
|
|
51
|
+
<button id="confirmInfo">Info</button>
|
|
52
|
+
<button id="confirmSuccess">Éxito</button>
|
|
53
|
+
<button id="confirmError">Error</button>
|
|
54
|
+
<button id="confirmWarning">Advertencia</button>
|
|
55
|
+
</div>
|
|
56
|
+
|
|
57
|
+
<script type="module">
|
|
58
|
+
import upop from './upop.js'
|
|
59
|
+
|
|
60
|
+
// Alerts
|
|
61
|
+
document.getElementById("alertInfo").addEventListener("click", () => {
|
|
62
|
+
upop.alert.info("Esto es un alert info");
|
|
63
|
+
});
|
|
64
|
+
document.getElementById("alertSuccess").addEventListener("click", () => {
|
|
65
|
+
upop.alert.success("Operación exitosa!");
|
|
66
|
+
});
|
|
67
|
+
document.getElementById("alertError").addEventListener("click", () => {
|
|
68
|
+
upop.alert.error("Ha ocurrido un error");
|
|
69
|
+
});
|
|
70
|
+
document.getElementById("alertWarning").addEventListener("click", () => {
|
|
71
|
+
upop.alert.warning("Cuidado con esta acción");
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// Toasts
|
|
75
|
+
document.getElementById("toastInfo").addEventListener("click", () => {
|
|
76
|
+
upop.toast.info("Esto es un toast info", 3000, "bottom-left");
|
|
77
|
+
});
|
|
78
|
+
document.getElementById("toastSuccess").addEventListener("click", () => {
|
|
79
|
+
upop.toast.success("Guardado con éxito!", 3000, "top-right");
|
|
80
|
+
});
|
|
81
|
+
document.getElementById("toastError").addEventListener("click", () => {
|
|
82
|
+
upop.toast.error("Error en la operación", 3000, "top-left");
|
|
83
|
+
});
|
|
84
|
+
document.getElementById("toastWarning").addEventListener("click", () => {
|
|
85
|
+
upop.toast.warning("Revisa los datos ingresados");
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// Confirms (usan upop en callbacks)
|
|
89
|
+
document.getElementById("confirmInfo").addEventListener("click", () => {
|
|
90
|
+
upop.confirm.info("¿Seguro que quieres continuar?", {
|
|
91
|
+
onConfirm: () => upop.alert.success("Confirmado ✅")
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
document.getElementById("confirmSuccess").addEventListener("click", () => {
|
|
95
|
+
upop.confirm.success("¿Deseas guardar los cambios?", {
|
|
96
|
+
textoAceptar: 'Guardar',
|
|
97
|
+
textoCancelar: 'Cancelar',
|
|
98
|
+
onConfirm: () => upop.toast.success("Cambios guardados!")
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
document.getElementById("confirmError").addEventListener("click", () => {
|
|
102
|
+
upop.confirm.error("¿Seguro que quieres borrar este registro?", {
|
|
103
|
+
textoAceptar: 'Eliminar',
|
|
104
|
+
textoCancelar: 'Cancelar',
|
|
105
|
+
onConfirm: () => upop.alert.error("Eliminado ❌")
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
document.getElementById("confirmWarning").addEventListener("click", () => {
|
|
109
|
+
upop.confirm.warning("¿Seguro que quieres cerrar sesión?", {
|
|
110
|
+
textoAceptar: 'Cerrar sesión',
|
|
111
|
+
textoCancelar: 'Volver',
|
|
112
|
+
onConfirm: () => upop.toast.success("Sesión cerrada")
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
</script>
|
|
116
|
+
</body>
|
|
117
|
+
</html>
|
package/src/upop.css
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
@import url('https://fonts.googleapis.com/css2?family=Geist:wght@100..900&display=swap');
|
|
2
|
+
|
|
3
|
+
/* ===================== */
|
|
4
|
+
/* MODALES */
|
|
5
|
+
/* ===================== */
|
|
6
|
+
.alerta-overlay {
|
|
7
|
+
position: fixed; inset: 0;
|
|
8
|
+
display: flex; justify-content: center; align-items: center;
|
|
9
|
+
width: 100%; height: 100%;
|
|
10
|
+
background: rgba(0,0,0,.45);
|
|
11
|
+
opacity: 0; pointer-events: none;
|
|
12
|
+
transition: opacity .25s ease;
|
|
13
|
+
z-index: 9999;
|
|
14
|
+
font-family: 'Geist', sans-serif;
|
|
15
|
+
|
|
16
|
+
&.visible {
|
|
17
|
+
opacity: 1; pointer-events: auto;
|
|
18
|
+
|
|
19
|
+
.alerta-modal { transform: translateY(0); }
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.alerta-modal {
|
|
24
|
+
background: #fff;
|
|
25
|
+
border-radius: 16px;
|
|
26
|
+
padding: 28px 24px;
|
|
27
|
+
max-width: 420px; width: 90%;
|
|
28
|
+
text-align: center;
|
|
29
|
+
box-shadow: 0 6px 20px rgba(0,0,0,.12);
|
|
30
|
+
transform: translateY(-15px);
|
|
31
|
+
transition: transform .25s ease;
|
|
32
|
+
|
|
33
|
+
p { font-size: 15px; margin-bottom: 22px; color: #333; line-height: 1.5; }
|
|
34
|
+
|
|
35
|
+
.alerta-boton {
|
|
36
|
+
border: none; border-radius: 8px;
|
|
37
|
+
padding: 10px 22px;
|
|
38
|
+
cursor: pointer;
|
|
39
|
+
font-size: 14px; font-weight: 500;
|
|
40
|
+
transition: background .2s ease, transform .1s ease;
|
|
41
|
+
color: #fff;
|
|
42
|
+
|
|
43
|
+
&:active { transform: scale(.97); }
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
&.alerta-info { border-top: 4px solid #0d6efd; .alerta-boton { background: #0d6efd; &:hover { background: #0b5ed7; } } }
|
|
47
|
+
&.alerta-exito { border-top: 4px solid #198754; .alerta-boton { background: #198754; &:hover { background: #146c43; } } }
|
|
48
|
+
&.alerta-error { border-top: 4px solid #dc3545; .alerta-boton { background: #dc3545; &:hover { background: #b02a37; } } }
|
|
49
|
+
&.alerta-advertencia { border-top: 4px solid #ffc107; .alerta-boton { background: #ffc107; color:#000; &:hover { background:#e0a800; color:#fff; } } }
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/* ===================== */
|
|
53
|
+
/* TOASTERS */
|
|
54
|
+
/* ===================== */
|
|
55
|
+
.alerta-contenedor {
|
|
56
|
+
position: fixed;
|
|
57
|
+
display: flex;
|
|
58
|
+
flex-direction: column;
|
|
59
|
+
gap: 12px;
|
|
60
|
+
z-index: 9999;
|
|
61
|
+
font-family: 'Geist', sans-serif;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.alerta-contenedor.top-right {
|
|
65
|
+
top: 20px; right: 20px;
|
|
66
|
+
align-items: flex-end;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.alerta-contenedor.top-left {
|
|
70
|
+
top: 20px; left: 20px;
|
|
71
|
+
align-items: flex-start;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.alerta-contenedor.bottom-right {
|
|
75
|
+
bottom: 20px; right: 20px;
|
|
76
|
+
align-items: flex-end;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.alerta-contenedor.bottom-left {
|
|
80
|
+
bottom: 20px; left: 20px;
|
|
81
|
+
align-items: flex-start;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.alerta {
|
|
85
|
+
opacity: 0; transform: translateY(-10px);
|
|
86
|
+
transition: opacity .3s ease, transform .3s ease;
|
|
87
|
+
padding: 14px 20px;
|
|
88
|
+
border-radius: 12px;
|
|
89
|
+
font-size: 14px; font-weight: 500;
|
|
90
|
+
background: #fff; color: #333;
|
|
91
|
+
box-shadow: 0 4px 12px rgba(0,0,0,.08);
|
|
92
|
+
border-left: 5px solid transparent;
|
|
93
|
+
max-width: 320px;
|
|
94
|
+
|
|
95
|
+
&.visible { opacity: 1; transform: translateY(0); }
|
|
96
|
+
&.alerta-info { border-left-color: #0d6efd; }
|
|
97
|
+
&.alerta-exito { border-left-color: #198754; }
|
|
98
|
+
&.alerta-error { border-left-color: #dc3545; }
|
|
99
|
+
&.alerta-advertencia { border-left-color: #ffc107; }
|
|
100
|
+
}
|
|
101
|
+
/* Botonera de confirm */
|
|
102
|
+
.alerta-botones {
|
|
103
|
+
display: flex;
|
|
104
|
+
justify-content: flex-end;
|
|
105
|
+
gap: 12px;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.alerta-boton.cancelar {
|
|
109
|
+
background: #e0e0e0;
|
|
110
|
+
color: #333;
|
|
111
|
+
}
|
|
112
|
+
.alerta-boton.cancelar:hover {
|
|
113
|
+
background: #c9c9c9;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.alerta-boton.aceptar {
|
|
117
|
+
font-weight: 600;
|
|
118
|
+
}
|
|
119
|
+
/* Botonera de confirm */
|
|
120
|
+
.alerta-botones {
|
|
121
|
+
display: flex;
|
|
122
|
+
justify-content: center; /* centrado */
|
|
123
|
+
gap: 14px;
|
|
124
|
+
}
|
package/src/upop.js
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
// upop.js
|
|
2
|
+
|
|
3
|
+
function crearModal(mensaje, {
|
|
4
|
+
tipo = "info",
|
|
5
|
+
botonTexto = "Aceptar",
|
|
6
|
+
onClose = () => {}
|
|
7
|
+
} = {}) {
|
|
8
|
+
if (document.querySelector(".alerta-overlay")) return;
|
|
9
|
+
|
|
10
|
+
const overlay = document.createElement("div");
|
|
11
|
+
overlay.className = "alerta-overlay";
|
|
12
|
+
|
|
13
|
+
const modal = document.createElement("div");
|
|
14
|
+
modal.className = `alerta-modal alerta-${tipo}`;
|
|
15
|
+
|
|
16
|
+
const texto = document.createElement("p");
|
|
17
|
+
texto.textContent = mensaje;
|
|
18
|
+
|
|
19
|
+
const boton = document.createElement("button");
|
|
20
|
+
boton.textContent = botonTexto;
|
|
21
|
+
boton.className = "alerta-boton";
|
|
22
|
+
boton.onclick = () => {
|
|
23
|
+
overlay.remove();
|
|
24
|
+
onClose();
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
modal.appendChild(texto);
|
|
28
|
+
modal.appendChild(boton);
|
|
29
|
+
overlay.appendChild(modal);
|
|
30
|
+
document.body.appendChild(overlay);
|
|
31
|
+
|
|
32
|
+
setTimeout(() => overlay.classList.add("visible"), 0);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function crearToast(mensaje, tipo = "info", duracion = 3000, posicion = "top-right") {
|
|
36
|
+
const contenedor = document.querySelector(`.alerta-contenedor.${posicion}`) || crearContenedor(posicion);
|
|
37
|
+
|
|
38
|
+
const alerta = document.createElement("div");
|
|
39
|
+
alerta.className = `alerta alerta-${tipo}`;
|
|
40
|
+
alerta.textContent = mensaje;
|
|
41
|
+
|
|
42
|
+
contenedor.appendChild(alerta);
|
|
43
|
+
setTimeout(() => alerta.classList.add("visible"), 50);
|
|
44
|
+
|
|
45
|
+
setTimeout(() => {
|
|
46
|
+
alerta.classList.remove("visible");
|
|
47
|
+
alerta.addEventListener("transitionend", () => alerta.remove());
|
|
48
|
+
}, duracion);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function crearContenedor(posicion = "top-right") {
|
|
52
|
+
const contenedor = document.createElement("div");
|
|
53
|
+
contenedor.className = `alerta-contenedor ${posicion}`;
|
|
54
|
+
document.body.appendChild(contenedor);
|
|
55
|
+
return contenedor;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// upop.js
|
|
59
|
+
|
|
60
|
+
function crearConfirm(mensaje, {
|
|
61
|
+
tipo = "info",
|
|
62
|
+
textoAceptar = "Aceptar",
|
|
63
|
+
textoCancelar = "Cancelar",
|
|
64
|
+
onConfirm = () => {},
|
|
65
|
+
onCancel = () => {}
|
|
66
|
+
} = {}) {
|
|
67
|
+
if (document.querySelector(".alerta-overlay")) return;
|
|
68
|
+
|
|
69
|
+
const overlay = document.createElement("div");
|
|
70
|
+
overlay.className = "alerta-overlay";
|
|
71
|
+
|
|
72
|
+
const modal = document.createElement("div");
|
|
73
|
+
modal.className = `alerta-modal alerta-${tipo}`;
|
|
74
|
+
|
|
75
|
+
const texto = document.createElement("p");
|
|
76
|
+
texto.textContent = mensaje;
|
|
77
|
+
|
|
78
|
+
const botones = document.createElement("div");
|
|
79
|
+
botones.className = "alerta-botones";
|
|
80
|
+
|
|
81
|
+
const btnCancelar = document.createElement("button");
|
|
82
|
+
btnCancelar.textContent = textoCancelar;
|
|
83
|
+
btnCancelar.className = "alerta-boton cancelar";
|
|
84
|
+
btnCancelar.onclick = () => {
|
|
85
|
+
overlay.remove();
|
|
86
|
+
onCancel();
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const btnAceptar = document.createElement("button");
|
|
90
|
+
btnAceptar.textContent = textoAceptar;
|
|
91
|
+
btnAceptar.className = "alerta-boton aceptar";
|
|
92
|
+
btnAceptar.onclick = () => {
|
|
93
|
+
overlay.remove();
|
|
94
|
+
onConfirm();
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
botones.appendChild(btnCancelar);
|
|
98
|
+
botones.appendChild(btnAceptar);
|
|
99
|
+
|
|
100
|
+
modal.appendChild(texto);
|
|
101
|
+
modal.appendChild(botones);
|
|
102
|
+
overlay.appendChild(modal);
|
|
103
|
+
document.body.appendChild(overlay);
|
|
104
|
+
|
|
105
|
+
setTimeout(() => overlay.classList.add("visible"), 0);
|
|
106
|
+
}
|
|
107
|
+
// Export nombrado
|
|
108
|
+
export const alert = {
|
|
109
|
+
info: (msg, opts={}) => crearModal(msg, { ...opts, tipo: "info" }),
|
|
110
|
+
success: (msg, opts={}) => crearModal(msg, { ...opts, tipo: "exito" }),
|
|
111
|
+
error: (msg, opts={}) => crearModal(msg, { ...opts, tipo: "error" }),
|
|
112
|
+
warning: (msg, opts={}) => crearModal(msg, { ...opts, tipo: "advertencia" }),
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
export const toast = {
|
|
116
|
+
info: (msg, dur, pos) => crearToast(msg, "info", dur, pos),
|
|
117
|
+
success: (msg, dur, pos) => crearToast(msg, "exito", dur, pos),
|
|
118
|
+
error: (msg, dur, pos) => crearToast(msg, "error", dur, pos),
|
|
119
|
+
warning: (msg, dur, pos) => crearToast(msg, "advertencia", dur, pos),
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
// Agregamos confirm al export
|
|
123
|
+
export const confirm = {
|
|
124
|
+
info: (msg, opts={}) => crearConfirm(msg, { ...opts, tipo: "info" }),
|
|
125
|
+
success: (msg, opts={}) => crearConfirm(msg, { ...opts, tipo: "exito" }),
|
|
126
|
+
error: (msg, opts={}) => crearConfirm(msg, { ...opts, tipo: "error" }),
|
|
127
|
+
warning: (msg, opts={}) => crearConfirm(msg, { ...opts, tipo: "advertencia" }),
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
// Export por defecto ahora con confirm
|
|
131
|
+
export default {
|
|
132
|
+
alert,
|
|
133
|
+
toast,
|
|
134
|
+
confirm
|
|
135
|
+
};
|