next-recomponents 2.0.4 → 2.0.6
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/dist/index.d.mts +6 -4
- package/dist/index.d.ts +6 -4
- package/dist/index.js +359 -252
- package/dist/index.mjs +357 -250
- package/package.json +1 -1
- package/src/pop/index.tsx +179 -73
- package/src/table/index.tsx +348 -241
package/package.json
CHANGED
package/src/pop/index.tsx
CHANGED
|
@@ -1,17 +1,110 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { useState } from "react";
|
|
3
3
|
|
|
4
|
+
type Color =
|
|
5
|
+
| "white"
|
|
6
|
+
| "primary"
|
|
7
|
+
| "secondary"
|
|
8
|
+
| "info"
|
|
9
|
+
| "danger"
|
|
10
|
+
| "warning"
|
|
11
|
+
| "success";
|
|
12
|
+
|
|
13
|
+
// ─── Color tokens ─────────────────────────────────────────────────────────────
|
|
14
|
+
|
|
15
|
+
const COLOR_CONFIG: Record<
|
|
16
|
+
Color,
|
|
17
|
+
{
|
|
18
|
+
bg: string;
|
|
19
|
+
iconBg: string;
|
|
20
|
+
iconText: string;
|
|
21
|
+
border: string;
|
|
22
|
+
confirm: string;
|
|
23
|
+
label: string;
|
|
24
|
+
}
|
|
25
|
+
> = {
|
|
26
|
+
primary: {
|
|
27
|
+
bg: "from-blue-50 to-indigo-50",
|
|
28
|
+
iconBg: "bg-blue-100",
|
|
29
|
+
iconText: "text-blue-600",
|
|
30
|
+
border: "border-blue-200",
|
|
31
|
+
confirm: "bg-blue-600 hover:bg-blue-700 focus:ring-blue-300",
|
|
32
|
+
label: "ℹ",
|
|
33
|
+
},
|
|
34
|
+
info: {
|
|
35
|
+
bg: "from-sky-50 to-cyan-50",
|
|
36
|
+
iconBg: "bg-sky-100",
|
|
37
|
+
iconText: "text-sky-600",
|
|
38
|
+
border: "border-sky-200",
|
|
39
|
+
confirm: "bg-sky-600 hover:bg-sky-700 focus:ring-sky-300",
|
|
40
|
+
label: "ℹ",
|
|
41
|
+
},
|
|
42
|
+
success: {
|
|
43
|
+
bg: "from-emerald-50 to-green-50",
|
|
44
|
+
iconBg: "bg-emerald-100",
|
|
45
|
+
iconText: "text-emerald-600",
|
|
46
|
+
border: "border-emerald-200",
|
|
47
|
+
confirm: "bg-emerald-600 hover:bg-emerald-700 focus:ring-emerald-300",
|
|
48
|
+
label: "✓",
|
|
49
|
+
},
|
|
50
|
+
warning: {
|
|
51
|
+
bg: "from-amber-50 to-yellow-50",
|
|
52
|
+
iconBg: "bg-amber-100",
|
|
53
|
+
iconText: "text-amber-600",
|
|
54
|
+
border: "border-amber-200",
|
|
55
|
+
confirm: "bg-amber-500 hover:bg-amber-600 focus:ring-amber-300",
|
|
56
|
+
label: "⚠",
|
|
57
|
+
},
|
|
58
|
+
danger: {
|
|
59
|
+
bg: "from-red-50 to-rose-50",
|
|
60
|
+
iconBg: "bg-red-100",
|
|
61
|
+
iconText: "text-red-600",
|
|
62
|
+
border: "border-red-200",
|
|
63
|
+
confirm: "bg-red-600 hover:bg-red-700 focus:ring-red-300",
|
|
64
|
+
label: "✕",
|
|
65
|
+
},
|
|
66
|
+
secondary: {
|
|
67
|
+
bg: "from-slate-50 to-gray-50",
|
|
68
|
+
iconBg: "bg-slate-100",
|
|
69
|
+
iconText: "text-slate-600",
|
|
70
|
+
border: "border-slate-200",
|
|
71
|
+
confirm: "bg-slate-700 hover:bg-slate-800 focus:ring-slate-300",
|
|
72
|
+
label: "◎",
|
|
73
|
+
},
|
|
74
|
+
white: {
|
|
75
|
+
bg: "from-gray-50 to-white",
|
|
76
|
+
iconBg: "bg-gray-100",
|
|
77
|
+
iconText: "text-gray-500",
|
|
78
|
+
border: "border-gray-200",
|
|
79
|
+
confirm: "bg-gray-700 hover:bg-gray-800 focus:ring-gray-300",
|
|
80
|
+
label: "◎",
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
// ─── Types ────────────────────────────────────────────────────────────────────
|
|
85
|
+
|
|
86
|
+
interface PopupState {
|
|
87
|
+
type: "alert" | "confirm" | "prompt";
|
|
88
|
+
message: string;
|
|
89
|
+
visible: boolean;
|
|
90
|
+
inputValue: string;
|
|
91
|
+
onConfirm?: (value?: string) => void;
|
|
92
|
+
onCancel?: () => void;
|
|
93
|
+
color: Color;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// ─── Hook ─────────────────────────────────────────────────────────────────────
|
|
97
|
+
|
|
4
98
|
export default function usePopup() {
|
|
5
|
-
const [popup, setPopup] = useState<{
|
|
6
|
-
type: "alert"
|
|
7
|
-
message:
|
|
8
|
-
visible:
|
|
9
|
-
inputValue:
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
function alert(message: string): Promise<void> {
|
|
99
|
+
const [popup, setPopup] = useState<PopupState>({
|
|
100
|
+
type: "alert",
|
|
101
|
+
message: "",
|
|
102
|
+
visible: false,
|
|
103
|
+
inputValue: "",
|
|
104
|
+
color: "primary",
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
function alert(message: string, color: Color = "primary"): Promise<void> {
|
|
15
108
|
return new Promise((resolve) => {
|
|
16
109
|
setPopup({
|
|
17
110
|
type: "alert",
|
|
@@ -19,11 +112,15 @@ export default function usePopup() {
|
|
|
19
112
|
visible: true,
|
|
20
113
|
inputValue: "",
|
|
21
114
|
onConfirm: () => resolve(),
|
|
115
|
+
color,
|
|
22
116
|
});
|
|
23
117
|
});
|
|
24
118
|
}
|
|
25
119
|
|
|
26
|
-
function confirm(
|
|
120
|
+
function confirm(
|
|
121
|
+
message: string,
|
|
122
|
+
color: Color = "primary",
|
|
123
|
+
): Promise<boolean> {
|
|
27
124
|
return new Promise((resolve) => {
|
|
28
125
|
setPopup({
|
|
29
126
|
type: "confirm",
|
|
@@ -32,11 +129,15 @@ export default function usePopup() {
|
|
|
32
129
|
inputValue: "",
|
|
33
130
|
onConfirm: () => resolve(true),
|
|
34
131
|
onCancel: () => resolve(false),
|
|
132
|
+
color,
|
|
35
133
|
});
|
|
36
134
|
});
|
|
37
135
|
}
|
|
38
136
|
|
|
39
|
-
function prompt(
|
|
137
|
+
function prompt(
|
|
138
|
+
message: string,
|
|
139
|
+
color: Color = "primary",
|
|
140
|
+
): Promise<string | null> {
|
|
40
141
|
return new Promise((resolve) => {
|
|
41
142
|
setPopup({
|
|
42
143
|
type: "prompt",
|
|
@@ -45,6 +146,7 @@ export default function usePopup() {
|
|
|
45
146
|
inputValue: "",
|
|
46
147
|
onConfirm: (value) => resolve(value ?? ""),
|
|
47
148
|
onCancel: () => resolve(null),
|
|
149
|
+
color,
|
|
48
150
|
});
|
|
49
151
|
});
|
|
50
152
|
}
|
|
@@ -57,86 +159,90 @@ export default function usePopup() {
|
|
|
57
159
|
});
|
|
58
160
|
}
|
|
59
161
|
|
|
162
|
+
const c = COLOR_CONFIG[popup.color];
|
|
163
|
+
|
|
60
164
|
const PopupComponent = popup.visible ? (
|
|
61
165
|
<div
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
left: 0,
|
|
66
|
-
width: "100%",
|
|
67
|
-
height: "100%",
|
|
68
|
-
background: "rgba(0,0,0,0.5)",
|
|
69
|
-
display: "flex",
|
|
70
|
-
alignItems: "center",
|
|
71
|
-
justifyContent: "center",
|
|
72
|
-
zIndex: 1000,
|
|
73
|
-
}}
|
|
166
|
+
className="fixed inset-0 flex items-center justify-center z-[1000]"
|
|
167
|
+
style={{ background: "rgba(15,23,42,0.45)", backdropFilter: "blur(2px)" }}
|
|
168
|
+
onClick={(e) => e.target === e.currentTarget && close(false)}
|
|
74
169
|
>
|
|
75
170
|
<div
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
boxShadow: "0 4px 20px rgba(0,0,0,0.2)",
|
|
83
|
-
}}
|
|
171
|
+
className={`
|
|
172
|
+
bg-gradient-to-br ${c.bg} border ${c.border}
|
|
173
|
+
rounded-2xl shadow-2xl w-full max-w-sm mx-4
|
|
174
|
+
animate-[fadeInScale_0.18s_ease-out]
|
|
175
|
+
`}
|
|
176
|
+
style={{ animation: "fadeInScale 0.18s ease-out" }}
|
|
84
177
|
>
|
|
85
|
-
<
|
|
178
|
+
<style>{`
|
|
179
|
+
@keyframes fadeInScale {
|
|
180
|
+
from { opacity: 0; transform: scale(0.93) translateY(8px); }
|
|
181
|
+
to { opacity: 1; transform: scale(1) translateY(0); }
|
|
182
|
+
}
|
|
183
|
+
`}</style>
|
|
86
184
|
|
|
185
|
+
{/* Icon + Message */}
|
|
186
|
+
<div className="flex flex-col items-center gap-3 px-8 pt-8 pb-5 text-center">
|
|
187
|
+
<div
|
|
188
|
+
className={`w-12 h-12 rounded-full ${c.iconBg} flex items-center justify-center`}
|
|
189
|
+
>
|
|
190
|
+
<span className={`text-xl font-bold ${c.iconText}`}>{c.label}</span>
|
|
191
|
+
</div>
|
|
192
|
+
<p className="text-gray-800 text-[15px] font-medium leading-snug">
|
|
193
|
+
{popup.message}
|
|
194
|
+
</p>
|
|
195
|
+
</div>
|
|
196
|
+
|
|
197
|
+
{/* Prompt input */}
|
|
87
198
|
{popup.type === "prompt" && (
|
|
88
|
-
<
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
e
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
199
|
+
<div className="px-8 pb-2">
|
|
200
|
+
<input
|
|
201
|
+
autoFocus
|
|
202
|
+
type="text"
|
|
203
|
+
value={popup.inputValue}
|
|
204
|
+
onChange={(e) =>
|
|
205
|
+
setPopup((prev) => ({ ...prev, inputValue: e.target.value }))
|
|
206
|
+
}
|
|
207
|
+
onKeyDown={(e) =>
|
|
208
|
+
e.key === "Enter" && close(true, popup.inputValue)
|
|
209
|
+
}
|
|
210
|
+
className={`
|
|
211
|
+
w-full px-3 py-2 rounded-lg border ${c.border} bg-white
|
|
212
|
+
text-sm text-gray-800 outline-none
|
|
213
|
+
focus:ring-2 ${c.confirm.includes("blue") ? "focus:ring-blue-200" : "focus:ring-gray-200"}
|
|
214
|
+
transition
|
|
215
|
+
`}
|
|
216
|
+
placeholder="Escribe aquí..."
|
|
217
|
+
/>
|
|
218
|
+
</div>
|
|
108
219
|
)}
|
|
109
220
|
|
|
110
|
-
|
|
221
|
+
{/* Divider */}
|
|
222
|
+
<div className={`border-t ${c.border} mx-0 mt-4`} />
|
|
223
|
+
|
|
224
|
+
{/* Actions */}
|
|
225
|
+
<div className="flex gap-2 px-6 py-4 justify-end">
|
|
111
226
|
{(popup.type === "confirm" || popup.type === "prompt") && (
|
|
112
227
|
<button
|
|
113
228
|
onClick={() => close(false)}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
borderRadius: "6px",
|
|
120
|
-
cursor: "pointer",
|
|
121
|
-
fontSize: "14px",
|
|
122
|
-
}}
|
|
229
|
+
className="
|
|
230
|
+
px-4 py-2 rounded-lg text-sm font-medium
|
|
231
|
+
bg-white border border-gray-200 text-gray-600
|
|
232
|
+
hover:bg-gray-50 transition
|
|
233
|
+
"
|
|
123
234
|
>
|
|
124
235
|
Cancelar
|
|
125
236
|
</button>
|
|
126
237
|
)}
|
|
127
238
|
<button
|
|
128
239
|
onClick={() => close(true, popup.inputValue)}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
border: "none",
|
|
134
|
-
borderRadius: "6px",
|
|
135
|
-
cursor: "pointer",
|
|
136
|
-
fontSize: "14px",
|
|
137
|
-
}}
|
|
240
|
+
className={`
|
|
241
|
+
px-5 py-2 rounded-lg text-sm font-semibold text-white
|
|
242
|
+
${c.confirm} transition focus:outline-none focus:ring-2
|
|
243
|
+
`}
|
|
138
244
|
>
|
|
139
|
-
|
|
245
|
+
Aceptar
|
|
140
246
|
</button>
|
|
141
247
|
</div>
|
|
142
248
|
</div>
|