@olwiba/ui 0.2.2 → 0.2.4

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.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { cn } from './chunk-AMWLSHD6.js';
2
2
  export { MdxContent, cn } from './chunk-AMWLSHD6.js';
3
- import * as React32 from 'react';
3
+ import * as React33 from 'react';
4
4
  import { useRef, useEffect, useState } from 'react';
5
5
  import { Button as Button$1, Card as Card$1, Input as Input$1, Textarea as Textarea$1, Checkbox as Checkbox$1, Switch as Switch$1, useIsMobile, UIVariantProvider, Badge as Badge$1, cn as cn$1, Table, TableHeader, TableRow, TableHead, TableBody, TableCell, Avatar, AvatarImage, AvatarFallback, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, Dialog, DialogTrigger, Progress, useUIVariant, Separator, Accordion, AccordionItem, AccordionTrigger, AccordionContent, Label, Sheet, SheetTrigger, SheetContent, StatusIndicator, CommandDialog, CommandInput, CommandList, CommandEmpty, CommandSeparator, CommandGroup, CommandItem, TooltipProvider, Tooltip, TooltipTrigger, TooltipContent, ContextMenu as ContextMenu$1, ContextMenuTrigger, ContextMenuContent, AlertDialog, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction, CommandShortcut, Popover, PopoverTrigger, PopoverContent, Spinner, SidebarProvider, SidebarInset, CardHeader, CardTitle, CardDescription, CardContent, InputOTP, InputOTPGroup, InputOTPSlot, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, DialogClose, ContextMenuSeparator, ContextMenuLabel, ContextMenuSub, ContextMenuSubTrigger, ContextMenuSubContent, ContextMenuItem, ContextMenuShortcut, Sidebar, SidebarHeader, SidebarMenu, SidebarMenuItem, SidebarMenuButton, SidebarContent, SidebarGroup, SidebarGroupContent, SidebarFooter, SidebarTrigger, useSidebar, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuGroup } from '@olwiba/cn';
6
6
  export { CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Enchanted } from '@olwiba/cn';
@@ -13,7 +13,7 @@ import { CSS } from '@dnd-kit/utilities';
13
13
  import { PieChart, Pie, Cell, BarChart, XAxis, YAxis, Bar, AreaChart, Area, LineChart, Line, ResponsiveContainer, Tooltip as Tooltip$1, CartesianGrid } from 'recharts';
14
14
  import { toast } from 'sonner';
15
15
 
16
- var OlwibaUIContext = React32.createContext({
16
+ var OlwibaUIContext = React33.createContext({
17
17
  isMobile: false,
18
18
  mode: "default",
19
19
  setMode: () => {
@@ -22,17 +22,17 @@ var OlwibaUIContext = React32.createContext({
22
22
  function OlwibaUIProvider({ children, isMobile: isMobileProp, mode: initialMode = "default" }) {
23
23
  const detectedMobile = useIsMobile();
24
24
  const isMobile = isMobileProp ?? detectedMobile;
25
- const [mode, setMode] = React32.useState(initialMode);
25
+ const [mode, setMode] = React33.useState(initialMode);
26
26
  const variant = mode !== "default" ? mode : void 0;
27
27
  return /* @__PURE__ */ jsx(OlwibaUIContext.Provider, { value: { isMobile, mode, setMode }, children: /* @__PURE__ */ jsx(UIVariantProvider, { mode: variant, children }) });
28
28
  }
29
29
  function useOlwibaUI() {
30
- return React32.useContext(OlwibaUIContext);
30
+ return React33.useContext(OlwibaUIContext);
31
31
  }
32
32
  function useUIMode() {
33
- return React32.useContext(OlwibaUIContext).mode;
33
+ return React33.useContext(OlwibaUIContext).mode;
34
34
  }
35
- var Button = React32.forwardRef(
35
+ var Button = React33.forwardRef(
36
36
  ({ mode, ...props }, ref) => {
37
37
  const ctxMode = useUIMode();
38
38
  const resolvedMode = mode ?? (ctxMode !== "default" ? ctxMode : void 0);
@@ -40,7 +40,7 @@ var Button = React32.forwardRef(
40
40
  }
41
41
  );
42
42
  Button.displayName = "Button";
43
- var Card = React32.forwardRef(
43
+ var Card = React33.forwardRef(
44
44
  ({ mode, ...props }, ref) => {
45
45
  const ctxMode = useUIMode();
46
46
  const resolvedMode = mode ?? (ctxMode !== "default" ? ctxMode : void 0);
@@ -51,7 +51,7 @@ Card.displayName = "Card";
51
51
  function Badge(props) {
52
52
  return /* @__PURE__ */ jsx(Badge$1, { ...props });
53
53
  }
54
- var Input = React32.forwardRef(
54
+ var Input = React33.forwardRef(
55
55
  ({ mode, ...props }, ref) => {
56
56
  const ctxMode = useUIMode();
57
57
  const resolvedMode = mode ?? (ctxMode !== "default" ? ctxMode : void 0);
@@ -59,7 +59,7 @@ var Input = React32.forwardRef(
59
59
  }
60
60
  );
61
61
  Input.displayName = "Input";
62
- var Textarea = React32.forwardRef(
62
+ var Textarea = React33.forwardRef(
63
63
  ({ mode, ...props }, ref) => {
64
64
  const ctxMode = useUIMode();
65
65
  const resolvedMode = mode ?? (ctxMode !== "default" ? ctxMode : void 0);
@@ -67,13 +67,13 @@ var Textarea = React32.forwardRef(
67
67
  }
68
68
  );
69
69
  Textarea.displayName = "Textarea";
70
- var Checkbox = React32.forwardRef(({ mode, ...props }, ref) => {
70
+ var Checkbox = React33.forwardRef(({ mode, ...props }, ref) => {
71
71
  const ctxMode = useUIMode();
72
72
  const resolvedMode = mode ?? (ctxMode !== "default" ? ctxMode : void 0);
73
73
  return /* @__PURE__ */ jsx(Checkbox$1, { mode: resolvedMode, ...props, ref });
74
74
  });
75
75
  Checkbox.displayName = "Checkbox";
76
- var Switch = React32.forwardRef(({ mode: _mode, ...props }, ref) => {
76
+ var Switch = React33.forwardRef(({ mode: _mode, ...props }, ref) => {
77
77
  return /* @__PURE__ */ jsx(Switch$1, { ...props, ref });
78
78
  });
79
79
  Switch.displayName = "Switch";
@@ -530,7 +530,7 @@ function DefaultForm({
530
530
  const isForgotPassword = mode === "forgot-password";
531
531
  const isResetPassword = mode === "reset-password";
532
532
  const isVerify = mode === "verify";
533
- const [code, setCode] = React32.useState("");
533
+ const [code, setCode] = React33.useState("");
534
534
  const hasPrefill = !!(defaultEmail || defaultPassword);
535
535
  const prefillStyle = (active) => active ? { animation: "auth-prefill 1.6s ease-out 0.35s 1 both" } : void 0;
536
536
  const copy = authCopy[mode];
@@ -690,10 +690,10 @@ function DataTable({
690
690
  emptyMessage = "No results.",
691
691
  className
692
692
  }) {
693
- const [sorting, setSorting] = React32.useState([]);
694
- const [rowSelection, setRowSelection] = React32.useState({});
695
- const [globalFilter, setGlobalFilter] = React32.useState("");
696
- const allColumns = React32.useMemo(
693
+ const [sorting, setSorting] = React33.useState([]);
694
+ const [rowSelection, setRowSelection] = React33.useState({});
695
+ const [globalFilter, setGlobalFilter] = React33.useState("");
696
+ const allColumns = React33.useMemo(
697
697
  () => selectable ? [selectColumn, ...columns] : columns,
698
698
  [selectable, columns]
699
699
  );
@@ -715,7 +715,7 @@ function DataTable({
715
715
  initialState: pageSize > 0 ? { pagination: { pageSize } } : void 0,
716
716
  enableRowSelection: selectable
717
717
  });
718
- React32.useEffect(() => {
718
+ React33.useEffect(() => {
719
719
  if (!onSelectionChange) return;
720
720
  onSelectionChange(table.getSelectedRowModel().rows.map((r) => r.original));
721
721
  }, [rowSelection]);
@@ -795,8 +795,8 @@ function DataTable({
795
795
  ] });
796
796
  }
797
797
  function InviteDialog({ roles, onInvite, onClose }) {
798
- const [email, setEmail] = React32.useState("");
799
- const [role, setRole] = React32.useState(roles[roles.length - 1] ?? roles[0]);
798
+ const [email, setEmail] = React33.useState("");
799
+ const [role, setRole] = React33.useState(roles[roles.length - 1] ?? roles[0]);
800
800
  return /* @__PURE__ */ jsx(DialogContent, { children: /* @__PURE__ */ jsxs(
801
801
  "form",
802
802
  {
@@ -840,8 +840,8 @@ function TeamMembersPanel({
840
840
  title = "Team members",
841
841
  description = "Manage who has access to this workspace."
842
842
  }) {
843
- const [inviteOpen, setInviteOpen] = React32.useState(false);
844
- const columns = React32.useMemo(() => [
843
+ const [inviteOpen, setInviteOpen] = React33.useState(false);
844
+ const columns = React33.useMemo(() => [
845
845
  {
846
846
  accessorKey: "name",
847
847
  header: "Name",
@@ -910,7 +910,7 @@ function BillingPanel({
910
910
  onUpdatePaymentMethod,
911
911
  className
912
912
  }) {
913
- const invoiceColumns = React32.useMemo(() => [
913
+ const invoiceColumns = React33.useMemo(() => [
914
914
  { accessorKey: "date", header: "Date", enableSorting: false },
915
915
  { accessorKey: "amount", header: "Amount", enableSorting: false },
916
916
  {
@@ -989,9 +989,9 @@ function OnboardingWizard({
989
989
  completeLabel = "Finish",
990
990
  className
991
991
  }) {
992
- const [internalStep, setInternalStep] = React32.useState(0);
993
- const [error, setError] = React32.useState(null);
994
- const [pending, setPending] = React32.useState(false);
992
+ const [internalStep, setInternalStep] = React33.useState(0);
993
+ const [error, setError] = React33.useState(null);
994
+ const [pending, setPending] = React33.useState(false);
995
995
  const index = stepProp ?? internalStep;
996
996
  const current = steps[index];
997
997
  const isLast = index === steps.length - 1;
@@ -1325,9 +1325,9 @@ function FadeIn({
1325
1325
  style,
1326
1326
  ...props
1327
1327
  }) {
1328
- const ref = React32.useRef(null);
1329
- const [visible, setVisible] = React32.useState(false);
1330
- React32.useEffect(() => {
1328
+ const ref = React33.useRef(null);
1329
+ const [visible, setVisible] = React33.useState(false);
1330
+ React33.useEffect(() => {
1331
1331
  const el = ref.current;
1332
1332
  if (!el) return;
1333
1333
  const observer = new IntersectionObserver(
@@ -1522,16 +1522,16 @@ function Carousel({
1522
1522
  className
1523
1523
  }) {
1524
1524
  const mode = useUIVariant();
1525
- const trackRef = React32.useRef(null);
1526
- const [canPrev, setCanPrev] = React32.useState(false);
1527
- const [canNext, setCanNext] = React32.useState(true);
1528
- const updateScrollState = React32.useCallback(() => {
1525
+ const trackRef = React33.useRef(null);
1526
+ const [canPrev, setCanPrev] = React33.useState(false);
1527
+ const [canNext, setCanNext] = React33.useState(true);
1528
+ const updateScrollState = React33.useCallback(() => {
1529
1529
  const track = trackRef.current;
1530
1530
  if (!track) return;
1531
1531
  setCanPrev(track.scrollLeft > 8);
1532
1532
  setCanNext(track.scrollLeft < track.scrollWidth - track.clientWidth - 8);
1533
1533
  }, []);
1534
- React32.useEffect(() => {
1534
+ React33.useEffect(() => {
1535
1535
  const track = trackRef.current;
1536
1536
  if (!track) return;
1537
1537
  updateScrollState();
@@ -1588,7 +1588,7 @@ function Carousel({
1588
1588
  role: "region",
1589
1589
  "aria-label": ariaLabel,
1590
1590
  className: "flex snap-x snap-mandatory gap-6 overflow-x-auto pb-4 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
1591
- children: React32.Children.map(
1591
+ children: React33.Children.map(
1592
1592
  children,
1593
1593
  (child) => child == null ? null : /* @__PURE__ */ jsx("div", { "data-carousel-item": true, className: cn$1("shrink-0 snap-start", itemClassName), children: child })
1594
1594
  )
@@ -1613,9 +1613,9 @@ function StaggerChildren({
1613
1613
  className,
1614
1614
  ...props
1615
1615
  }) {
1616
- const ref = React32.useRef(null);
1617
- const [visible, setVisible] = React32.useState(false);
1618
- React32.useEffect(() => {
1616
+ const ref = React33.useRef(null);
1617
+ const [visible, setVisible] = React33.useState(false);
1618
+ React33.useEffect(() => {
1619
1619
  const el = ref.current;
1620
1620
  if (!el) return;
1621
1621
  const observer = new IntersectionObserver(
@@ -1633,7 +1633,7 @@ function StaggerChildren({
1633
1633
  return () => observer.disconnect();
1634
1634
  }, [once]);
1635
1635
  const [tx, ty] = translateMap2[direction];
1636
- return /* @__PURE__ */ jsx("div", { ref, className: cn$1(className), ...props, children: React32.Children.map(children, (child, i) => /* @__PURE__ */ jsx(
1636
+ return /* @__PURE__ */ jsx("div", { ref, className: cn$1(className), ...props, children: React33.Children.map(children, (child, i) => /* @__PURE__ */ jsx(
1637
1637
  "div",
1638
1638
  {
1639
1639
  className: "h-full",
@@ -1709,11 +1709,56 @@ function GroupedFeaturesSection({
1709
1709
  ] }, group.label)) })
1710
1710
  ] }) }) });
1711
1711
  }
1712
+ function TimelineGroup({
1713
+ steps,
1714
+ startNumber,
1715
+ fadeIn
1716
+ }) {
1717
+ const fadePx = 48;
1718
+ return /* @__PURE__ */ jsxs("div", { className: "relative", children: [
1719
+ fadeIn && /* @__PURE__ */ jsx(
1720
+ "div",
1721
+ {
1722
+ "aria-hidden": "true",
1723
+ className: "absolute left-[19px] w-1 bg-gradient-to-b from-transparent to-primary",
1724
+ style: { top: 0, height: fadePx }
1725
+ }
1726
+ ),
1727
+ /* @__PURE__ */ jsx(
1728
+ "div",
1729
+ {
1730
+ "aria-hidden": "true",
1731
+ className: "absolute left-[19px] w-1 bg-primary",
1732
+ style: {
1733
+ top: fadeIn ? fadePx : 20,
1734
+ height: fadeIn ? `calc(100% - ${fadePx}px)` : "calc(100% - 20px)"
1735
+ }
1736
+ }
1737
+ ),
1738
+ /* @__PURE__ */ jsx(
1739
+ "div",
1740
+ {
1741
+ "aria-hidden": "true",
1742
+ className: "absolute left-[19px] w-1 bg-gradient-to-b from-primary to-transparent",
1743
+ style: { top: "100%", height: fadePx }
1744
+ }
1745
+ ),
1746
+ /* @__PURE__ */ jsx("div", { className: "space-y-10", style: fadeIn ? { paddingTop: fadePx } : void 0, children: steps.map((step, i) => /* @__PURE__ */ jsx(FadeIn, { direction: "up", delay: i * 80, children: /* @__PURE__ */ jsxs("div", { className: "relative flex gap-5", children: [
1747
+ /* @__PURE__ */ jsx("div", { className: "relative z-10 flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-full border-2 border-primary bg-primary text-lg font-bold text-primary-foreground", children: step.emoji ?? startNumber + i }),
1748
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 pt-1 pb-2", children: [
1749
+ /* @__PURE__ */ jsx("h3", { className: "mb-2 text-xl font-semibold text-foreground", children: step.title }),
1750
+ /* @__PURE__ */ jsx("div", { className: "text-sm leading-relaxed text-muted-foreground", children: step.description })
1751
+ ] })
1752
+ ] }) }, step.title)) })
1753
+ ] });
1754
+ }
1712
1755
  function StepsSection({
1713
1756
  badge = "How it works",
1714
1757
  title = "From zero to shipped",
1715
1758
  description,
1716
- steps
1759
+ steps,
1760
+ variant = "default",
1761
+ groups
1717
1762
  }) {
1718
1763
  const mode = useUIVariant();
1719
1764
  const sectionClasses = cn$1(
@@ -1722,11 +1767,27 @@ function StepsSection({
1722
1767
  mode === "playful" && "rounded-2xl border-primary/25 border",
1723
1768
  !mode && "rounded-2xl border"
1724
1769
  );
1770
+ if (variant === "timeline") {
1771
+ const resolvedGroups = groups ?? (steps ? [{ steps }] : []);
1772
+ let nextNumber = 1;
1773
+ return /* @__PURE__ */ jsx("section", { className: sectionClasses, children: /* @__PURE__ */ jsx("div", { className: "px-6 py-14 sm:px-10 sm:py-20", children: /* @__PURE__ */ jsxs("div", { className: "mx-auto max-w-3xl", children: [
1774
+ /* @__PURE__ */ jsx(SectionTitle, { badge, title, description, className: "text-left [&>p]:mx-0" }),
1775
+ /* @__PURE__ */ jsx("div", { className: "mt-12", children: resolvedGroups.map((group, groupIndex) => {
1776
+ const startNumber = nextNumber;
1777
+ nextNumber += group.steps.length;
1778
+ return /* @__PURE__ */ jsxs(React33.Fragment, { children: [
1779
+ /* @__PURE__ */ jsx("div", { className: cn$1(groupIndex > 0 && "mt-10"), children: /* @__PURE__ */ jsx(TimelineGroup, { steps: group.steps, startNumber, fadeIn: groupIndex > 0 }) }),
1780
+ group.after && /* @__PURE__ */ jsx("div", { className: "mt-16", children: group.after })
1781
+ ] }, groupIndex);
1782
+ }) })
1783
+ ] }) }) });
1784
+ }
1785
+ const resolvedSteps = steps ?? [];
1725
1786
  return /* @__PURE__ */ jsx("section", { className: sectionClasses, children: /* @__PURE__ */ jsx("div", { className: "px-6 py-14 sm:px-10 sm:py-20", children: /* @__PURE__ */ jsxs("div", { className: "mx-auto max-w-4xl", children: [
1726
1787
  /* @__PURE__ */ jsx(SectionTitle, { badge, title, description }),
1727
1788
  /* @__PURE__ */ jsxs("div", { className: "mt-12", children: [
1728
- /* @__PURE__ */ jsx("div", { className: "hidden sm:grid", style: { gridTemplateColumns: `repeat(${steps.length}, 1fr)` }, children: steps.map((step, i) => /* @__PURE__ */ jsx(FadeIn, { direction: "up", delay: i * 80, children: /* @__PURE__ */ jsxs("div", { className: "relative flex flex-col items-center text-center px-4", children: [
1729
- i < steps.length - 1 && /* @__PURE__ */ jsx(
1789
+ /* @__PURE__ */ jsx("div", { className: "hidden sm:grid", style: { gridTemplateColumns: `repeat(${resolvedSteps.length}, 1fr)` }, children: resolvedSteps.map((step, i) => /* @__PURE__ */ jsx(FadeIn, { direction: "up", delay: i * 80, children: /* @__PURE__ */ jsxs("div", { className: "relative flex flex-col items-center text-center px-4", children: [
1790
+ i < resolvedSteps.length - 1 && /* @__PURE__ */ jsx(
1730
1791
  "div",
1731
1792
  {
1732
1793
  "aria-hidden": "true",
@@ -1735,10 +1796,10 @@ function StepsSection({
1735
1796
  ),
1736
1797
  /* @__PURE__ */ jsx("div", { className: "relative z-10 mb-3 flex h-12 w-12 items-center justify-center rounded-full bg-muted text-2xl", children: step.emoji ?? /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-primary", children: i + 1 }) }),
1737
1798
  /* @__PURE__ */ jsx("h3", { className: "font-semibold text-foreground", children: step.title }),
1738
- /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm leading-relaxed text-muted-foreground", children: step.description })
1799
+ /* @__PURE__ */ jsx("div", { className: "mt-2 text-sm leading-relaxed text-muted-foreground", children: step.description })
1739
1800
  ] }) }, step.title)) }),
1740
- /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-0 sm:hidden", children: steps.map((step, i) => /* @__PURE__ */ jsx(FadeIn, { direction: "up", delay: i * 80, children: /* @__PURE__ */ jsxs("div", { className: "relative flex gap-4 pb-8 last:pb-0", children: [
1741
- i < steps.length - 1 && /* @__PURE__ */ jsx(
1801
+ /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-0 sm:hidden", children: resolvedSteps.map((step, i) => /* @__PURE__ */ jsx(FadeIn, { direction: "up", delay: i * 80, children: /* @__PURE__ */ jsxs("div", { className: "relative flex gap-4 pb-8 last:pb-0", children: [
1802
+ i < resolvedSteps.length - 1 && /* @__PURE__ */ jsx(
1742
1803
  "div",
1743
1804
  {
1744
1805
  "aria-hidden": "true",
@@ -1748,7 +1809,7 @@ function StepsSection({
1748
1809
  /* @__PURE__ */ jsx("div", { className: "relative z-10 flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full bg-muted text-2xl", children: step.emoji ?? /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-primary", children: i + 1 }) }),
1749
1810
  /* @__PURE__ */ jsxs("div", { className: "pt-3", children: [
1750
1811
  /* @__PURE__ */ jsx("h3", { className: "font-semibold text-foreground", children: step.title }),
1751
- /* @__PURE__ */ jsx("p", { className: "mt-1.5 text-sm leading-relaxed text-muted-foreground", children: step.description })
1812
+ /* @__PURE__ */ jsx("div", { className: "mt-1.5 text-sm leading-relaxed text-muted-foreground", children: step.description })
1752
1813
  ] })
1753
1814
  ] }) }, step.title)) })
1754
1815
  ] })
@@ -1884,9 +1945,9 @@ function FeatureMarqueeSection({
1884
1945
  ] });
1885
1946
  }
1886
1947
  function useIntersectionObserver(options) {
1887
- const ref = React32.useRef(null);
1888
- const [isIntersecting, setIsIntersecting] = React32.useState(false);
1889
- React32.useEffect(() => {
1948
+ const ref = React33.useRef(null);
1949
+ const [isIntersecting, setIsIntersecting] = React33.useState(false);
1950
+ React33.useEffect(() => {
1890
1951
  const el = ref.current;
1891
1952
  if (!el) return;
1892
1953
  const observer = new IntersectionObserver(([entry]) => {
@@ -1908,8 +1969,8 @@ function ShowcaseCta({
1908
1969
  sectionClasses
1909
1970
  }) {
1910
1971
  const [ref, intersecting] = useIntersectionObserver({ threshold: 0.15 });
1911
- const [visible, setVisible] = React32.useState(false);
1912
- React32.useEffect(() => {
1972
+ const [visible, setVisible] = React33.useState(false);
1973
+ React33.useEffect(() => {
1913
1974
  if (intersecting) setVisible(true);
1914
1975
  }, [intersecting]);
1915
1976
  return /* @__PURE__ */ jsxs(
@@ -2086,8 +2147,8 @@ function CountdownTimer({
2086
2147
  className,
2087
2148
  compact = false
2088
2149
  }) {
2089
- const [timeLeft, setTimeLeft] = React32.useState(() => getTimeLeft(deadline));
2090
- React32.useEffect(() => {
2150
+ const [timeLeft, setTimeLeft] = React33.useState(() => getTimeLeft(deadline));
2151
+ React33.useEffect(() => {
2091
2152
  setTimeLeft(getTimeLeft(deadline));
2092
2153
  const id = setInterval(() => setTimeLeft(getTimeLeft(deadline)), 1e3);
2093
2154
  return () => clearInterval(id);
@@ -2113,7 +2174,7 @@ function CountdownTimer({
2113
2174
  ];
2114
2175
  return /* @__PURE__ */ jsxs("div", { className: cn$1("flex items-center justify-center gap-2 text-sm", className), children: [
2115
2176
  /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: label }),
2116
- /* @__PURE__ */ jsx("span", { className: "flex items-center gap-1 font-mono font-semibold tabular-nums", children: units.map(({ value, unit }, i) => /* @__PURE__ */ jsxs(React32.Fragment, { children: [
2177
+ /* @__PURE__ */ jsx("span", { className: "flex items-center gap-1 font-mono font-semibold tabular-nums", children: units.map(({ value, unit }, i) => /* @__PURE__ */ jsxs(React33.Fragment, { children: [
2117
2178
  /* @__PURE__ */ jsxs("span", { children: [
2118
2179
  String(value).padStart(2, "0"),
2119
2180
  /* @__PURE__ */ jsx("span", { className: "font-normal text-muted-foreground", children: unit })
@@ -2134,9 +2195,11 @@ function PricingSection({
2134
2195
  footnote,
2135
2196
  mode = "subscription",
2136
2197
  foundingDeadline,
2198
+ currency = "$",
2199
+ highlightedBadgeLabel = "Founding member",
2137
2200
  renderPlanFooter
2138
2201
  }) {
2139
- const [annual, setAnnual] = React32.useState(false);
2202
+ const [annual, setAnnual] = React33.useState(false);
2140
2203
  const isOneTime = mode === "one-time";
2141
2204
  const uiMode = useUIVariant();
2142
2205
  const sectionClasses = cn$1(
@@ -2184,9 +2247,9 @@ function PricingSection({
2184
2247
  ] }),
2185
2248
  /* @__PURE__ */ jsx(StaggerChildren, { className: "mt-10 grid gap-4 lg:grid-cols-3", children: plans.map((plan) => {
2186
2249
  const rawPrice = isOneTime ? plan.monthly : annual ? plan.annual : plan.monthly;
2187
- const price = plan.priceDisplay ?? `$${rawPrice}`;
2250
+ const price = plan.priceDisplay ?? `${currency}${rawPrice}`;
2188
2251
  const period = plan.periodDisplay ?? (isOneTime ? "one-time" : rawPrice > 0 ? "/mo" : "");
2189
- const badge2 = plan.highlighted && foundingDeadline ? /* @__PURE__ */ jsx("span", { className: "inline-flex items-center rounded-full border bg-secondary px-2.5 py-0.5 text-xs font-semibold text-secondary-foreground", children: /* @__PURE__ */ jsx(CountdownTimer, { deadline: foundingDeadline, compact: true }) }) : plan.highlighted ? "Founding member" : void 0;
2252
+ const badge2 = plan.highlighted && foundingDeadline ? /* @__PURE__ */ jsx("span", { className: "inline-flex items-center rounded-full border bg-secondary px-2.5 py-0.5 text-xs font-semibold text-secondary-foreground", children: /* @__PURE__ */ jsx(CountdownTimer, { deadline: foundingDeadline, compact: true }) }) : plan.highlighted && highlightedBadgeLabel ? highlightedBadgeLabel : void 0;
2190
2253
  return /* @__PURE__ */ jsx(
2191
2254
  PricingCard,
2192
2255
  {
@@ -2405,10 +2468,10 @@ function CountUp({
2405
2468
  className,
2406
2469
  ...props
2407
2470
  }) {
2408
- const ref = React32.useRef(null);
2409
- const [value, setValue] = React32.useState(from);
2410
- const hasStarted = React32.useRef(false);
2411
- React32.useEffect(() => {
2471
+ const ref = React33.useRef(null);
2472
+ const [value, setValue] = React33.useState(from);
2473
+ const hasStarted = React33.useRef(false);
2474
+ React33.useEffect(() => {
2412
2475
  const el = ref.current;
2413
2476
  if (!el) return;
2414
2477
  const observer = new IntersectionObserver(
@@ -2501,8 +2564,8 @@ function NewsletterSection({
2501
2564
  successDescription = defaults.successDescription,
2502
2565
  onSubscribe
2503
2566
  } = {}) {
2504
- const [email, setEmail] = React32.useState("");
2505
- const [submitted, setSubmitted] = React32.useState(false);
2567
+ const [email, setEmail] = React33.useState("");
2568
+ const [submitted, setSubmitted] = React33.useState(false);
2506
2569
  const mode = useUIVariant();
2507
2570
  const sectionClasses = cn$1(
2508
2571
  "overflow-hidden bg-card",
@@ -2593,7 +2656,7 @@ function ContactSection({
2593
2656
  sendAnotherLabel = defaults2.sendAnotherLabel,
2594
2657
  onSubmit
2595
2658
  } = {}) {
2596
- const [submitted, setSubmitted] = React32.useState(false);
2659
+ const [submitted, setSubmitted] = React33.useState(false);
2597
2660
  const mode = useUIVariant();
2598
2661
  const sectionClasses = cn$1(
2599
2662
  "overflow-hidden bg-card",
@@ -2891,7 +2954,7 @@ function Navbar({
2891
2954
  controls,
2892
2955
  renderLink = defaultRenderLink7
2893
2956
  }) {
2894
- const [open, setOpen] = React32.useState(false);
2957
+ const [open, setOpen] = React33.useState(false);
2895
2958
  const brandHref = brand.href ?? "/";
2896
2959
  const hasRightContent = controls?.length || cta?.primary || cta?.secondary;
2897
2960
  return /* @__PURE__ */ jsx("section", { className: "overflow-hidden rounded-2xl border bg-card", children: /* @__PURE__ */ jsxs("nav", { className: "grid h-16 grid-cols-[1fr_auto_1fr] items-center px-6", children: [
@@ -2908,7 +2971,7 @@ function Navbar({
2908
2971
  children: link.label
2909
2972
  }) }, link.label)) }),
2910
2973
  hasRightContent && /* @__PURE__ */ jsxs("div", { className: "hidden items-center justify-end gap-2 md:flex", children: [
2911
- controls?.map((control, i) => /* @__PURE__ */ jsx(React32.Fragment, { children: control }, i)),
2974
+ controls?.map((control, i) => /* @__PURE__ */ jsx(React33.Fragment, { children: control }, i)),
2912
2975
  (cta?.secondary || cta?.primary) && controls?.length ? /* @__PURE__ */ jsx("div", { className: "mx-1 h-4 w-px bg-border" }) : null,
2913
2976
  cta?.secondary && renderLink({
2914
2977
  href: cta.secondary.href,
@@ -2932,7 +2995,7 @@ function Navbar({
2932
2995
  /* @__PURE__ */ jsx("span", { children: brand.name })
2933
2996
  ] })
2934
2997
  }) }) }),
2935
- controls?.length ? /* @__PURE__ */ jsx("div", { className: "mb-4 flex w-full items-center justify-between gap-1", children: controls.map((control, i) => /* @__PURE__ */ jsx(React32.Fragment, { children: control }, i)) }) : null,
2998
+ controls?.length ? /* @__PURE__ */ jsx("div", { className: "mb-4 flex w-full items-center justify-between gap-1", children: controls.map((control, i) => /* @__PURE__ */ jsx(React33.Fragment, { children: control }, i)) }) : null,
2936
2999
  /* @__PURE__ */ jsx(Separator, {}),
2937
3000
  /* @__PURE__ */ jsx("nav", { className: "mt-4 flex flex-col gap-1", children: navLinks.map((link) => /* @__PURE__ */ jsx("span", { onClick: () => setOpen(false), children: renderLink({
2938
3001
  href: link.href,
@@ -3081,7 +3144,7 @@ function LogoStrip({
3081
3144
  ] });
3082
3145
  }
3083
3146
  function GridUnderlay({ variant, size = 24, className, ...props }) {
3084
- const id = React32.useId();
3147
+ const id = React33.useId();
3085
3148
  const pattern = variant === "dots" ? /* @__PURE__ */ jsx("circle", { cx: size / 2, cy: size / 2, r: 1, fill: "currentColor" }) : variant === "lines" ? /* @__PURE__ */ jsx("path", { d: `M ${size} 0 L 0 0 0 ${size}`, fill: "none", stroke: "currentColor", strokeWidth: 0.5 }) : /* @__PURE__ */ jsxs(Fragment, { children: [
3086
3149
  /* @__PURE__ */ jsx("line", { x1: size / 2, y1: 0, x2: size / 2, y2: size, stroke: "currentColor", strokeWidth: 0.5 }),
3087
3150
  /* @__PURE__ */ jsx("line", { x1: 0, y1: size / 2, x2: size, y2: size / 2, stroke: "currentColor", strokeWidth: 0.5 })
@@ -3109,9 +3172,9 @@ function GlowUnderlay({
3109
3172
  style,
3110
3173
  ...props
3111
3174
  }) {
3112
- const [pos, setPos] = React32.useState({ x: "50%", y: "50%" });
3113
- const containerRef = React32.useRef(null);
3114
- React32.useEffect(() => {
3175
+ const [pos, setPos] = React33.useState({ x: "50%", y: "50%" });
3176
+ const containerRef = React33.useRef(null);
3177
+ React33.useEffect(() => {
3115
3178
  if (!followCursor) return;
3116
3179
  const handleMouseMove = (e) => {
3117
3180
  const el = containerRef.current;
@@ -3250,8 +3313,8 @@ function PageTransition({
3250
3313
  style,
3251
3314
  ...props
3252
3315
  }) {
3253
- const [mounted, setMounted] = React32.useState(false);
3254
- React32.useEffect(() => {
3316
+ const [mounted, setMounted] = React33.useState(false);
3317
+ React33.useEffect(() => {
3255
3318
  const id = requestAnimationFrame(() => setMounted(true));
3256
3319
  return () => cancelAnimationFrame(id);
3257
3320
  }, []);
@@ -3326,7 +3389,7 @@ function Sortable({
3326
3389
  if (oldIndex === -1 || newIndex === -1) return;
3327
3390
  onReorder(arrayMove(items, oldIndex, newIndex));
3328
3391
  };
3329
- const childArray = React32.Children.toArray(children);
3392
+ const childArray = React33.Children.toArray(children);
3330
3393
  return /* @__PURE__ */ jsx(DndContext, { sensors, collisionDetection: closestCenter, onDragEnd: handleDragEnd, children: /* @__PURE__ */ jsx(SortableContext, { items, strategy: strategies[direction], children: /* @__PURE__ */ jsx("div", { className: cn$1(containerClasses[direction], className), children: childArray.map(
3331
3394
  (child, i) => items[i] === void 0 ? null : /* @__PURE__ */ jsx(SortableItem, { id: items[i], disabled, className: itemClassName, children: child }, items[i])
3332
3395
  ) }) }) });
@@ -3338,8 +3401,8 @@ function Spotlight({
3338
3401
  triggerClassName,
3339
3402
  shortcut = "\u2318K"
3340
3403
  }) {
3341
- const [open, setOpen] = React32.useState(false);
3342
- React32.useEffect(() => {
3404
+ const [open, setOpen] = React33.useState(false);
3405
+ React33.useEffect(() => {
3343
3406
  const down = (e) => {
3344
3407
  if (e.key === "k" && (e.metaKey || e.ctrlKey)) {
3345
3408
  e.preventDefault();
@@ -3369,7 +3432,7 @@ function Spotlight({
3369
3432
  /* @__PURE__ */ jsx(CommandInput, { placeholder }),
3370
3433
  /* @__PURE__ */ jsxs(CommandList, { children: [
3371
3434
  /* @__PURE__ */ jsx(CommandEmpty, { children: "No results found." }),
3372
- groups.map((group, i) => /* @__PURE__ */ jsxs(React32.Fragment, { children: [
3435
+ groups.map((group, i) => /* @__PURE__ */ jsxs(React33.Fragment, { children: [
3373
3436
  i > 0 && /* @__PURE__ */ jsx(CommandSeparator, {}),
3374
3437
  /* @__PURE__ */ jsx(CommandGroup, { heading: group.heading, children: group.items.map((item) => /* @__PURE__ */ jsxs(
3375
3438
  CommandItem,
@@ -3394,8 +3457,8 @@ function Spotlight({
3394
3457
  var BASE = 40;
3395
3458
  var MAGNIFY_RADIUS = 80;
3396
3459
  function Dock({ items, iconSize = BASE, magnification = 1.7, className, ...props }) {
3397
- const [mouseX, setMouseX] = React32.useState(null);
3398
- const containerRef = React32.useRef(null);
3460
+ const [mouseX, setMouseX] = React33.useState(null);
3461
+ const containerRef = React33.useRef(null);
3399
3462
  function getScale(index) {
3400
3463
  if (mouseX === null || !containerRef.current) return 1;
3401
3464
  const container = containerRef.current;
@@ -3494,7 +3557,7 @@ function ConfirmDialog({ isOpen, options, handleConfirm, handleCancel, destructi
3494
3557
  ] }) });
3495
3558
  }
3496
3559
  function RegisterHotkeys({ hotkeys }) {
3497
- React32.useEffect(() => {
3560
+ React33.useEffect(() => {
3498
3561
  const handleKeyDown = (event) => {
3499
3562
  for (const hotkey of hotkeys) {
3500
3563
  const matches = event.key.toLowerCase() === hotkey.key.toLowerCase() && !!event.ctrlKey === !!hotkey.ctrl && !!event.metaKey === !!hotkey.meta && !!event.shiftKey === !!hotkey.shift && !!event.altKey === !!hotkey.alt;
@@ -3511,10 +3574,10 @@ function RegisterHotkeys({ hotkeys }) {
3511
3574
  return null;
3512
3575
  }
3513
3576
  function useControlledOpen(defaultOpen = false) {
3514
- const [isOpen, setIsOpen] = React32.useState(defaultOpen);
3515
- const open = React32.useCallback(() => setIsOpen(true), []);
3516
- const close = React32.useCallback(() => setIsOpen(false), []);
3517
- const toggle = React32.useCallback(() => setIsOpen((prev) => !prev), []);
3577
+ const [isOpen, setIsOpen] = React33.useState(defaultOpen);
3578
+ const open = React33.useCallback(() => setIsOpen(true), []);
3579
+ const close = React33.useCallback(() => setIsOpen(false), []);
3580
+ const toggle = React33.useCallback(() => setIsOpen((prev) => !prev), []);
3518
3581
  return { isOpen, open, close, toggle, setIsOpen };
3519
3582
  }
3520
3583
  function CommandMenu({
@@ -3527,7 +3590,7 @@ function CommandMenu({
3527
3590
  }) {
3528
3591
  const internal = useControlledOpen(false);
3529
3592
  const isOpen = openProp ?? internal.isOpen;
3530
- const setOpen = React32.useCallback(
3593
+ const setOpen = React33.useCallback(
3531
3594
  (next) => {
3532
3595
  if (openProp === void 0) internal.setIsOpen(next);
3533
3596
  onOpenChange?.(next);
@@ -3552,7 +3615,7 @@ function CommandMenu({
3552
3615
  /* @__PURE__ */ jsx(CommandInput, { placeholder }),
3553
3616
  /* @__PURE__ */ jsxs(CommandList, { children: [
3554
3617
  /* @__PURE__ */ jsx(CommandEmpty, { children: emptyMessage }),
3555
- groups.map((group, i) => /* @__PURE__ */ jsxs(React32.Fragment, { children: [
3618
+ groups.map((group, i) => /* @__PURE__ */ jsxs(React33.Fragment, { children: [
3556
3619
  i > 0 && /* @__PURE__ */ jsx(CommandSeparator, {}),
3557
3620
  /* @__PURE__ */ jsx(CommandGroup, { heading: group.heading, children: group.items.map((item) => /* @__PURE__ */ jsxs(
3558
3621
  CommandItem,
@@ -3744,20 +3807,20 @@ function FileUpload({
3744
3807
  hint,
3745
3808
  className
3746
3809
  }) {
3747
- const [internalFiles, setInternalFiles] = React32.useState(defaultFiles ?? []);
3748
- const [isDragging, setIsDragging] = React32.useState(false);
3749
- const [validationError, setValidationError] = React32.useState(null);
3750
- const inputRef = React32.useRef(null);
3751
- const dragDepth = React32.useRef(0);
3810
+ const [internalFiles, setInternalFiles] = React33.useState(defaultFiles ?? []);
3811
+ const [isDragging, setIsDragging] = React33.useState(false);
3812
+ const [validationError, setValidationError] = React33.useState(null);
3813
+ const inputRef = React33.useRef(null);
3814
+ const dragDepth = React33.useRef(0);
3752
3815
  const files = filesProp ?? internalFiles;
3753
- const setFiles = React32.useCallback(
3816
+ const setFiles = React33.useCallback(
3754
3817
  (next) => {
3755
3818
  if (!filesProp) setInternalFiles(next);
3756
3819
  onFilesChange?.(next);
3757
3820
  },
3758
3821
  [filesProp, onFilesChange]
3759
3822
  );
3760
- const acceptList = React32.useMemo(
3823
+ const acceptList = React33.useMemo(
3761
3824
  () => accept?.split(",").map((a) => a.trim().toLowerCase()).filter(Boolean) ?? [],
3762
3825
  [accept]
3763
3826
  );
@@ -4424,7 +4487,7 @@ function PageHeader({
4424
4487
  return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-1 pb-6", className), children: [
4425
4488
  breadcrumbs && breadcrumbs.length > 0 && /* @__PURE__ */ jsx("nav", { "aria-label": "Breadcrumb", className: "mb-2 flex items-center gap-1 text-sm text-muted-foreground", children: breadcrumbs.map((crumb, i) => {
4426
4489
  const isLast = i === breadcrumbs.length - 1;
4427
- return /* @__PURE__ */ jsxs(React32.Fragment, { children: [
4490
+ return /* @__PURE__ */ jsxs(React33.Fragment, { children: [
4428
4491
  i > 0 && /* @__PURE__ */ jsx(ChevronRight, { className: "size-3.5 shrink-0" }),
4429
4492
  isLast || !crumb.href ? /* @__PURE__ */ jsx("span", { className: cn(isLast && "text-foreground font-medium"), children: crumb.label }) : renderLink({
4430
4493
  href: crumb.href,
@@ -4460,7 +4523,7 @@ function PageHeader({
4460
4523
  ] });
4461
4524
  }
4462
4525
  function Suspensed({ children, fallback }) {
4463
- return /* @__PURE__ */ jsx(React32.Suspense, { fallback: fallback ?? /* @__PURE__ */ jsx(Spinner, {}), children });
4526
+ return /* @__PURE__ */ jsx(React33.Suspense, { fallback: fallback ?? /* @__PURE__ */ jsx(Spinner, {}), children });
4464
4527
  }
4465
4528
  function getInitialTheme() {
4466
4529
  if (typeof document === "undefined") return "dark";
@@ -4468,7 +4531,7 @@ function getInitialTheme() {
4468
4531
  return stored ?? (document.documentElement.classList.contains("dark") ? "dark" : "light");
4469
4532
  }
4470
4533
  function ThemeSwitchMinimal() {
4471
- const [theme, setThemeState] = React32.useState(getInitialTheme);
4534
+ const [theme, setThemeState] = React33.useState(getInitialTheme);
4472
4535
  const toggle = () => {
4473
4536
  const next = theme === "dark" ? "light" : "dark";
4474
4537
  setThemeState(next);
@@ -4594,9 +4657,9 @@ function getInitialColorName() {
4594
4657
  return localStorage.getItem(STORAGE_KEY) ?? "emerald";
4595
4658
  }
4596
4659
  function BrandColorSwitchMinimal() {
4597
- const [active, setActive] = React32.useState(getInitialColorName);
4598
- const [open, setOpen] = React32.useState(false);
4599
- React32.useEffect(() => {
4660
+ const [active, setActive] = React33.useState(getInitialColorName);
4661
+ const [open, setOpen] = React33.useState(false);
4662
+ React33.useEffect(() => {
4600
4663
  const saved = localStorage.getItem(STORAGE_KEY) ?? "emerald";
4601
4664
  const color = BRAND_COLORS.find((c) => c.name === saved);
4602
4665
  if (color) applyColor(color);
@@ -4657,7 +4720,7 @@ function BrandColorSwitchMinimal() {
4657
4720
  ] });
4658
4721
  }
4659
4722
  function ThemeColorUpdater({ colorTheme }) {
4660
- React32.useEffect(() => {
4723
+ React33.useEffect(() => {
4661
4724
  if (colorTheme) {
4662
4725
  document.documentElement.setAttribute("data-theme", colorTheme);
4663
4726
  } else {
@@ -4667,7 +4730,7 @@ function ThemeColorUpdater({ colorTheme }) {
4667
4730
  return null;
4668
4731
  }
4669
4732
  function VersionBanner({ version, message, className, onDismiss }) {
4670
- const [dismissed, setDismissed] = React32.useState(false);
4733
+ const [dismissed, setDismissed] = React33.useState(false);
4671
4734
  if (dismissed) return null;
4672
4735
  return /* @__PURE__ */ jsxs("div", { className: cn("flex items-center justify-between gap-4 bg-primary/10 px-4 py-2 text-sm", className), children: [
4673
4736
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
@@ -4924,29 +4987,29 @@ function useMounted() {
4924
4987
  return mounted;
4925
4988
  }
4926
4989
  function useConfirm() {
4927
- const [isOpen, setIsOpen] = React32.useState(false);
4928
- const [options, setOptions] = React32.useState({});
4929
- const resolveRef = React32.useRef(null);
4930
- const confirm = React32.useCallback((opts = {}) => {
4990
+ const [isOpen, setIsOpen] = React33.useState(false);
4991
+ const [options, setOptions] = React33.useState({});
4992
+ const resolveRef = React33.useRef(null);
4993
+ const confirm = React33.useCallback((opts = {}) => {
4931
4994
  setOptions(opts);
4932
4995
  setIsOpen(true);
4933
4996
  return new Promise((resolve) => {
4934
4997
  resolveRef.current = resolve;
4935
4998
  });
4936
4999
  }, []);
4937
- const handleConfirm = React32.useCallback(() => {
5000
+ const handleConfirm = React33.useCallback(() => {
4938
5001
  resolveRef.current?.(true);
4939
5002
  setIsOpen(false);
4940
5003
  }, []);
4941
- const handleCancel = React32.useCallback(() => {
5004
+ const handleCancel = React33.useCallback(() => {
4942
5005
  resolveRef.current?.(false);
4943
5006
  setIsOpen(false);
4944
5007
  }, []);
4945
5008
  return { confirm, isOpen, options, handleConfirm, handleCancel };
4946
5009
  }
4947
5010
  function useScrolledPast(threshold) {
4948
- const [scrolledPast, setScrolledPast] = React32.useState(false);
4949
- React32.useEffect(() => {
5011
+ const [scrolledPast, setScrolledPast] = React33.useState(false);
5012
+ React33.useEffect(() => {
4950
5013
  const handleScroll = () => {
4951
5014
  setScrolledPast(window.scrollY > threshold);
4952
5015
  };
@@ -4957,28 +5020,28 @@ function useScrolledPast(threshold) {
4957
5020
  return scrolledPast;
4958
5021
  }
4959
5022
  function useCopyToClipboard() {
4960
- const [copied, setCopied] = React32.useState(false);
4961
- const timeoutRef = React32.useRef(void 0);
4962
- const copy = React32.useCallback((text) => {
5023
+ const [copied, setCopied] = React33.useState(false);
5024
+ const timeoutRef = React33.useRef(void 0);
5025
+ const copy = React33.useCallback((text) => {
4963
5026
  navigator.clipboard.writeText(text).then(() => {
4964
5027
  setCopied(true);
4965
5028
  clearTimeout(timeoutRef.current);
4966
5029
  timeoutRef.current = setTimeout(() => setCopied(false), 2e3);
4967
5030
  });
4968
5031
  }, []);
4969
- React32.useEffect(() => () => clearTimeout(timeoutRef.current), []);
5032
+ React33.useEffect(() => () => clearTimeout(timeoutRef.current), []);
4970
5033
  return [copied, copy];
4971
5034
  }
4972
5035
  function useDebounce(value, delay) {
4973
- const [debounced, setDebounced] = React32.useState(value);
4974
- React32.useEffect(() => {
5036
+ const [debounced, setDebounced] = React33.useState(value);
5037
+ React33.useEffect(() => {
4975
5038
  const timer = setTimeout(() => setDebounced(value), delay);
4976
5039
  return () => clearTimeout(timer);
4977
5040
  }, [value, delay]);
4978
5041
  return debounced;
4979
5042
  }
4980
5043
  function useLocalStorage(key, initialValue) {
4981
- const [storedValue, setStoredValue] = React32.useState(() => {
5044
+ const [storedValue, setStoredValue] = React33.useState(() => {
4982
5045
  if (typeof window === "undefined") return initialValue;
4983
5046
  try {
4984
5047
  const item = window.localStorage.getItem(key);
@@ -4987,7 +5050,7 @@ function useLocalStorage(key, initialValue) {
4987
5050
  return initialValue;
4988
5051
  }
4989
5052
  });
4990
- const setValue = React32.useCallback(
5053
+ const setValue = React33.useCallback(
4991
5054
  (value) => {
4992
5055
  try {
4993
5056
  setStoredValue(value);
@@ -5002,11 +5065,11 @@ function useLocalStorage(key, initialValue) {
5002
5065
  return [storedValue, setValue];
5003
5066
  }
5004
5067
  function useMediaQuery(query) {
5005
- const [matches, setMatches] = React32.useState(() => {
5068
+ const [matches, setMatches] = React33.useState(() => {
5006
5069
  if (typeof window === "undefined") return false;
5007
5070
  return window.matchMedia(query).matches;
5008
5071
  });
5009
- React32.useEffect(() => {
5072
+ React33.useEffect(() => {
5010
5073
  if (typeof window === "undefined") return;
5011
5074
  const mql = window.matchMedia(query);
5012
5075
  setMatches(mql.matches);
@@ -5017,15 +5080,15 @@ function useMediaQuery(query) {
5017
5080
  return matches;
5018
5081
  }
5019
5082
  function usePagination(total, pageSize) {
5020
- const [page, setPage] = React32.useState(1);
5083
+ const [page, setPage] = React33.useState(1);
5021
5084
  const totalPages = Math.max(1, Math.ceil(total / pageSize));
5022
5085
  const offset = (page - 1) * pageSize;
5023
- const goTo = React32.useCallback(
5086
+ const goTo = React33.useCallback(
5024
5087
  (p) => setPage(Math.min(Math.max(1, p), totalPages)),
5025
5088
  [totalPages]
5026
5089
  );
5027
- const next = React32.useCallback(() => goTo(page + 1), [page, goTo]);
5028
- const prev = React32.useCallback(() => goTo(page - 1), [page, goTo]);
5090
+ const next = React33.useCallback(() => goTo(page + 1), [page, goTo]);
5091
+ const prev = React33.useCallback(() => goTo(page - 1), [page, goTo]);
5029
5092
  return { page, pageSize, totalPages, offset, hasPrev: page > 1, hasNext: page < totalPages, goTo, next, prev };
5030
5093
  }
5031
5094