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 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
+ };