@underverse-ui/underverse 0.2.29 → 0.2.31
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.cjs +100 -79
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +108 -87
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2382,6 +2382,8 @@ var Modal = ({
|
|
|
2382
2382
|
const [isMounted, setIsMounted] = React10.useState(false);
|
|
2383
2383
|
const [isVisible, setIsVisible] = React10.useState(false);
|
|
2384
2384
|
const [isAnimating, setIsAnimating] = React10.useState(true);
|
|
2385
|
+
const mouseDownTarget = React10.useRef(null);
|
|
2386
|
+
const modalContentRef = React10.useRef(null);
|
|
2385
2387
|
React10.useEffect(() => {
|
|
2386
2388
|
setIsMounted(true);
|
|
2387
2389
|
return () => setIsMounted(false);
|
|
@@ -2421,74 +2423,90 @@ var Modal = ({
|
|
|
2421
2423
|
document.body.style.overflow = "unset";
|
|
2422
2424
|
};
|
|
2423
2425
|
}, [isOpen]);
|
|
2424
|
-
const
|
|
2425
|
-
|
|
2426
|
+
const handleOverlayMouseDown = (event) => {
|
|
2427
|
+
mouseDownTarget.current = event.target;
|
|
2428
|
+
};
|
|
2429
|
+
const handleOverlayMouseUp = (event) => {
|
|
2430
|
+
const modalContent2 = modalContentRef.current;
|
|
2431
|
+
const mouseDownOutside = modalContent2 && !modalContent2.contains(mouseDownTarget.current);
|
|
2432
|
+
const mouseUpOutside = modalContent2 && !modalContent2.contains(event.target);
|
|
2433
|
+
if (closeOnOverlayClick && mouseDownOutside && mouseUpOutside) {
|
|
2426
2434
|
onClose();
|
|
2427
2435
|
}
|
|
2436
|
+
mouseDownTarget.current = null;
|
|
2428
2437
|
};
|
|
2429
2438
|
if (!isMounted || !isOpen && !isVisible) {
|
|
2430
2439
|
return null;
|
|
2431
2440
|
}
|
|
2432
2441
|
const maxWidthClass = width ? "max-w-none" : fullWidth ? "max-w-full" : sizeStyles3[size];
|
|
2433
|
-
const modalContent = /* @__PURE__ */ jsxs12(
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
"transition-all duration-200 ease-out",
|
|
2449
|
-
maxWidthClass,
|
|
2450
|
-
fullWidth && "mx-0",
|
|
2451
|
-
className
|
|
2442
|
+
const modalContent = /* @__PURE__ */ jsxs12(
|
|
2443
|
+
"div",
|
|
2444
|
+
{
|
|
2445
|
+
className: cn("fixed inset-0 z-9999 flex items-center justify-center", overlayClassName),
|
|
2446
|
+
onMouseDown: handleOverlayMouseDown,
|
|
2447
|
+
onMouseUp: handleOverlayMouseUp,
|
|
2448
|
+
children: [
|
|
2449
|
+
/* @__PURE__ */ jsx14(
|
|
2450
|
+
"div",
|
|
2451
|
+
{
|
|
2452
|
+
className: "absolute inset-0 bg-background/80 backdrop-blur-sm transition-opacity duration-200 ease-out",
|
|
2453
|
+
style: {
|
|
2454
|
+
opacity: isOpen && !isAnimating ? 1 : 0
|
|
2455
|
+
}
|
|
2456
|
+
}
|
|
2452
2457
|
),
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2458
|
+
/* @__PURE__ */ jsxs12(
|
|
2459
|
+
"div",
|
|
2460
|
+
{
|
|
2461
|
+
ref: modalContentRef,
|
|
2462
|
+
className: cn(
|
|
2463
|
+
"relative w-full rounded-lg bg-card text-card-foreground shadow-xl",
|
|
2464
|
+
"transition-all duration-200 ease-out",
|
|
2465
|
+
maxWidthClass,
|
|
2466
|
+
fullWidth && "mx-0",
|
|
2467
|
+
className
|
|
2468
|
+
),
|
|
2469
|
+
style: {
|
|
2470
|
+
opacity: isOpen && !isAnimating ? 1 : 0,
|
|
2471
|
+
transform: isOpen && !isAnimating ? "scale(1)" : "scale(0.9)",
|
|
2472
|
+
// Thêm dòng này để tạo hiệu ứng nảy
|
|
2473
|
+
transition: "all 300ms cubic-bezier(0.34, 1.76, 0.64, 1)",
|
|
2474
|
+
width,
|
|
2475
|
+
height
|
|
2476
|
+
},
|
|
2477
|
+
onClick: (e) => e.stopPropagation(),
|
|
2478
|
+
children: [
|
|
2479
|
+
(title || description || showCloseButton) && /* @__PURE__ */ jsxs12("div", { className: "flex items-start justify-between p-6 pb-0", children: [
|
|
2480
|
+
/* @__PURE__ */ jsxs12("div", { className: "space-y-1.5", children: [
|
|
2481
|
+
title && /* @__PURE__ */ jsx14("h2", { className: "text-lg font-semibold leading-none tracking-tight", children: title }),
|
|
2482
|
+
description && /* @__PURE__ */ jsx14("p", { className: "text-sm text-muted-foreground", children: description })
|
|
2483
|
+
] }),
|
|
2484
|
+
showCloseButton && /* @__PURE__ */ jsx14(
|
|
2485
|
+
"button",
|
|
2486
|
+
{
|
|
2487
|
+
onClick: onClose,
|
|
2488
|
+
className: cn(
|
|
2489
|
+
"rounded-sm opacity-70 ring-offset-background transition-opacity",
|
|
2490
|
+
"hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
|
|
2491
|
+
"disabled:pointer-events-none "
|
|
2492
|
+
),
|
|
2493
|
+
children: /* @__PURE__ */ jsx14(X4, { className: "h-4 w-4 cursor-pointer" })
|
|
2494
|
+
}
|
|
2495
|
+
)
|
|
2496
|
+
] }),
|
|
2497
|
+
/* @__PURE__ */ jsx14("div", { className: cn("p-6", noPadding && "p-0", contentClassName), children })
|
|
2498
|
+
]
|
|
2499
|
+
}
|
|
2500
|
+
)
|
|
2501
|
+
]
|
|
2502
|
+
}
|
|
2503
|
+
);
|
|
2486
2504
|
return typeof window !== "undefined" ? createPortal(modalContent, document.body) : null;
|
|
2487
2505
|
};
|
|
2488
2506
|
var Modal_default = Modal;
|
|
2489
2507
|
|
|
2490
2508
|
// ../../components/ui/Toast.tsx
|
|
2491
|
-
import { createContext, useContext, useState as useState9, useCallback as useCallback2, useEffect as useEffect2, useRef as
|
|
2509
|
+
import { createContext, useContext, useState as useState9, useCallback as useCallback2, useEffect as useEffect2, useRef as useRef4 } from "react";
|
|
2492
2510
|
import { X as X5, CheckCircle as CheckCircle2, AlertCircle as AlertCircle2, Info, AlertTriangle as AlertTriangle2 } from "lucide-react";
|
|
2493
2511
|
import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
2494
2512
|
var ToastContext = createContext(void 0);
|
|
@@ -2501,7 +2519,7 @@ var useToast = () => {
|
|
|
2501
2519
|
};
|
|
2502
2520
|
var ToastProvider = ({ children, position = "top-right", maxToasts = 5 }) => {
|
|
2503
2521
|
const [toasts, setToasts] = useState9([]);
|
|
2504
|
-
const idRef =
|
|
2522
|
+
const idRef = useRef4(0);
|
|
2505
2523
|
const removeToast = useCallback2((id) => {
|
|
2506
2524
|
setToasts((prev) => prev.filter((toast) => toast.id !== id));
|
|
2507
2525
|
}, []);
|
|
@@ -2513,11 +2531,6 @@ var ToastProvider = ({ children, position = "top-right", maxToasts = 5 }) => {
|
|
|
2513
2531
|
const updated = [newToast, ...prev];
|
|
2514
2532
|
return updated.slice(0, maxToasts);
|
|
2515
2533
|
});
|
|
2516
|
-
if (toast.duration !== 0) {
|
|
2517
|
-
setTimeout(() => {
|
|
2518
|
-
removeToast(id);
|
|
2519
|
-
}, toast.duration || 5e3);
|
|
2520
|
-
}
|
|
2521
2534
|
},
|
|
2522
2535
|
[maxToasts, removeToast]
|
|
2523
2536
|
);
|
|
@@ -2538,33 +2551,31 @@ var ToastComponent = ({ toast, onRemove }) => {
|
|
|
2538
2551
|
const [isVisible, setIsVisible] = useState9(false);
|
|
2539
2552
|
const [progress, setProgress] = useState9(100);
|
|
2540
2553
|
const [paused, setPaused] = useState9(false);
|
|
2541
|
-
const [startTs] = useState9(() => Date.now());
|
|
2542
2554
|
const total = toast.duration && toast.duration > 0 ? toast.duration : 5e3;
|
|
2543
|
-
const
|
|
2555
|
+
const endTsRef = useRef4(Date.now() + total);
|
|
2556
|
+
const remainingRef = useRef4(total);
|
|
2557
|
+
const pausedRef = useRef4(false);
|
|
2558
|
+
const handleRemove = useCallback2(() => {
|
|
2559
|
+
setIsVisible(false);
|
|
2560
|
+
setTimeout(() => onRemove(toast.id), 150);
|
|
2561
|
+
}, [onRemove, toast.id]);
|
|
2544
2562
|
useEffect2(() => {
|
|
2545
2563
|
setIsVisible(true);
|
|
2546
2564
|
if (toast.duration === 0) return;
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
const remain = Math.max(
|
|
2552
|
-
|
|
2565
|
+
remainingRef.current = total;
|
|
2566
|
+
endTsRef.current = Date.now() + total;
|
|
2567
|
+
const intervalId = window.setInterval(() => {
|
|
2568
|
+
if (!pausedRef.current) {
|
|
2569
|
+
const remain = Math.max(endTsRef.current - Date.now(), 0);
|
|
2570
|
+
remainingRef.current = remain;
|
|
2553
2571
|
setProgress(remain / total * 100);
|
|
2554
2572
|
if (remain === 0) {
|
|
2555
2573
|
handleRemove();
|
|
2556
|
-
return;
|
|
2557
2574
|
}
|
|
2558
2575
|
}
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
return () => cancelAnimationFrame(raf);
|
|
2563
|
-
}, []);
|
|
2564
|
-
const handleRemove = () => {
|
|
2565
|
-
setIsVisible(false);
|
|
2566
|
-
setTimeout(() => onRemove(toast.id), 150);
|
|
2567
|
-
};
|
|
2576
|
+
}, 50);
|
|
2577
|
+
return () => window.clearInterval(intervalId);
|
|
2578
|
+
}, [handleRemove, toast.duration, total]);
|
|
2568
2579
|
const typeConfig = {
|
|
2569
2580
|
success: {
|
|
2570
2581
|
icon: CheckCircle2,
|
|
@@ -2600,8 +2611,18 @@ var ToastComponent = ({ toast, onRemove }) => {
|
|
|
2600
2611
|
),
|
|
2601
2612
|
role: "status",
|
|
2602
2613
|
"aria-live": toast.type === "error" ? "assertive" : "polite",
|
|
2603
|
-
onMouseEnter: () =>
|
|
2604
|
-
|
|
2614
|
+
onMouseEnter: () => {
|
|
2615
|
+
if (toast.duration === 0) return;
|
|
2616
|
+
pausedRef.current = true;
|
|
2617
|
+
remainingRef.current = Math.max(endTsRef.current - Date.now(), 0);
|
|
2618
|
+
setPaused(true);
|
|
2619
|
+
},
|
|
2620
|
+
onMouseLeave: () => {
|
|
2621
|
+
if (toast.duration === 0) return;
|
|
2622
|
+
pausedRef.current = false;
|
|
2623
|
+
endTsRef.current = Date.now() + remainingRef.current;
|
|
2624
|
+
setPaused(false);
|
|
2625
|
+
},
|
|
2605
2626
|
children: [
|
|
2606
2627
|
/* @__PURE__ */ jsxs13("div", { className: "flex items-start gap-3 p-4", children: [
|
|
2607
2628
|
/* @__PURE__ */ jsx15(Icon, { className: cn("h-5 w-5 mt-0.5 shrink-0", config.iconClassName) }),
|
|
@@ -7762,7 +7783,7 @@ function CategoryTreeSelect({ categories, value, onChange, placeholder = "Ch\u1E
|
|
|
7762
7783
|
}
|
|
7763
7784
|
|
|
7764
7785
|
// ../../components/ui/ImageUpload.tsx
|
|
7765
|
-
import { useState as useState26, useRef as
|
|
7786
|
+
import { useState as useState26, useRef as useRef12, useCallback as useCallback9 } from "react";
|
|
7766
7787
|
import { Upload, X as X10, Image as ImageIcon, Loader2 as Loader25, Check as Check7 } from "lucide-react";
|
|
7767
7788
|
import { useTranslations as useTranslations6 } from "next-intl";
|
|
7768
7789
|
import { jsx as jsx36, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
@@ -7784,7 +7805,7 @@ function ImageUpload({
|
|
|
7784
7805
|
const [isDragging, setIsDragging] = useState26(false);
|
|
7785
7806
|
const [uploading, setUploading] = useState26(false);
|
|
7786
7807
|
const [uploadedImages, setUploadedImages] = useState26([]);
|
|
7787
|
-
const fileInputRef =
|
|
7808
|
+
const fileInputRef = useRef12(null);
|
|
7788
7809
|
const { addToast } = useToast();
|
|
7789
7810
|
const t = useTranslations6("OCR.imageUpload");
|
|
7790
7811
|
const previewSizes = {
|
|
@@ -10923,7 +10944,7 @@ function AccessDenied({
|
|
|
10923
10944
|
|
|
10924
10945
|
// ../../components/ui/ThemeToggleHeadless.tsx
|
|
10925
10946
|
import { Moon, Sun, Monitor } from "lucide-react";
|
|
10926
|
-
import { useEffect as useEffect20, useRef as
|
|
10947
|
+
import { useEffect as useEffect20, useRef as useRef14, useState as useState33 } from "react";
|
|
10927
10948
|
import { createPortal as createPortal10 } from "react-dom";
|
|
10928
10949
|
import { Fragment as Fragment18, jsx as jsx52, jsxs as jsxs47 } from "react/jsx-runtime";
|
|
10929
10950
|
function ThemeToggleHeadless({
|
|
@@ -10934,7 +10955,7 @@ function ThemeToggleHeadless({
|
|
|
10934
10955
|
}) {
|
|
10935
10956
|
const [isOpen, setIsOpen] = useState33(false);
|
|
10936
10957
|
const [mounted, setMounted] = useState33(false);
|
|
10937
|
-
const triggerRef =
|
|
10958
|
+
const triggerRef = useRef14(null);
|
|
10938
10959
|
const [dropdownPosition, setDropdownPosition] = useState33(null);
|
|
10939
10960
|
useEffect20(() => setMounted(true), []);
|
|
10940
10961
|
const themes = [
|
|
@@ -11025,7 +11046,7 @@ function ThemeToggleHeadless({
|
|
|
11025
11046
|
}
|
|
11026
11047
|
|
|
11027
11048
|
// ../../components/ui/LanguageSwitcherHeadless.tsx
|
|
11028
|
-
import { useRef as
|
|
11049
|
+
import { useRef as useRef15, useState as useState34 } from "react";
|
|
11029
11050
|
import { createPortal as createPortal11 } from "react-dom";
|
|
11030
11051
|
import { Globe } from "lucide-react";
|
|
11031
11052
|
import { Fragment as Fragment19, jsx as jsx53, jsxs as jsxs48 } from "react/jsx-runtime";
|
|
@@ -11038,7 +11059,7 @@ function LanguageSwitcherHeadless({
|
|
|
11038
11059
|
}) {
|
|
11039
11060
|
const [isOpen, setIsOpen] = useState34(false);
|
|
11040
11061
|
const [dropdownPosition, setDropdownPosition] = useState34(null);
|
|
11041
|
-
const triggerButtonRef =
|
|
11062
|
+
const triggerButtonRef = useRef15(null);
|
|
11042
11063
|
const currentLanguage = locales.find((l) => l.code === currentLocale) || locales[0];
|
|
11043
11064
|
const calculatePosition = () => {
|
|
11044
11065
|
const rect = triggerButtonRef.current?.getBoundingClientRect();
|