@olwiba/ui 0.2.4 → 0.2.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.js CHANGED
@@ -1,11 +1,11 @@
1
1
  import { cn } from './chunk-AMWLSHD6.js';
2
2
  export { MdxContent, cn } from './chunk-AMWLSHD6.js';
3
- import * as React33 from 'react';
3
+ import * as React34 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';
7
7
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
8
- import { Search, ArrowUp, ArrowDown, ArrowUpDown, ChevronLeft, ChevronRight, MoreHorizontal, UserPlus, Download, CreditCard, Check, Loader2, ArrowLeft, ArrowUpRight, X, ArrowRight, Sparkles, Minus, Quote, Star, Twitter, Github, Linkedin, Mail, MessageSquare, ChevronDown, Send, Menu, UploadCloud, File, CheckCircle2, AlertCircle, Bell, Inbox, Activity, TrendingUp, TrendingDown, Sun, Moon, Palette, AlertTriangle, Rocket, Info, Layers, LayoutGrid, ShieldCheck, Building2, MoreVerticalIcon, CreditCardIcon, BellIcon, LogOutIcon } from 'lucide-react';
8
+ import { Search, ArrowUp, ArrowDown, ArrowUpDown, ChevronLeft, ChevronRight, MoreHorizontal, UserPlus, Download, CreditCard, Check, Loader2, ArrowLeft, ArrowUpRight, X, Sparkles, RefreshCw, ArrowRight, Minus, Quote, Star, Twitter, Github, Linkedin, Mail, MessageSquare, ChevronDown, Send, Menu, UploadCloud, File, CheckCircle2, AlertCircle, Bell, Inbox, Activity, TrendingUp, TrendingDown, Sun, Moon, Palette, AlertTriangle, Rocket, Info, Layers, LayoutGrid, ShieldCheck, Building2, MoreVerticalIcon, CreditCardIcon, BellIcon, LogOutIcon } from 'lucide-react';
9
9
  import { useReactTable, getPaginationRowModel, getSortedRowModel, getCoreRowModel, flexRender } from '@tanstack/react-table';
10
10
  import { useSensors, useSensor, PointerSensor, KeyboardSensor, DndContext, closestCenter } from '@dnd-kit/core';
11
11
  import { sortableKeyboardCoordinates, SortableContext, rectSortingStrategy, horizontalListSortingStrategy, verticalListSortingStrategy, arrayMove, useSortable } from '@dnd-kit/sortable';
@@ -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 = React33.createContext({
16
+ var OlwibaUIContext = React34.createContext({
17
17
  isMobile: false,
18
18
  mode: "default",
19
19
  setMode: () => {
@@ -22,17 +22,17 @@ var OlwibaUIContext = React33.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] = React33.useState(initialMode);
25
+ const [mode, setMode] = React34.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 React33.useContext(OlwibaUIContext);
30
+ return React34.useContext(OlwibaUIContext);
31
31
  }
32
32
  function useUIMode() {
33
- return React33.useContext(OlwibaUIContext).mode;
33
+ return React34.useContext(OlwibaUIContext).mode;
34
34
  }
35
- var Button = React33.forwardRef(
35
+ var Button = React34.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 = React33.forwardRef(
40
40
  }
41
41
  );
42
42
  Button.displayName = "Button";
43
- var Card = React33.forwardRef(
43
+ var Card = React34.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 = React33.forwardRef(
54
+ var Input = React34.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 = React33.forwardRef(
59
59
  }
60
60
  );
61
61
  Input.displayName = "Input";
62
- var Textarea = React33.forwardRef(
62
+ var Textarea = React34.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 = React33.forwardRef(
67
67
  }
68
68
  );
69
69
  Textarea.displayName = "Textarea";
70
- var Checkbox = React33.forwardRef(({ mode, ...props }, ref) => {
70
+ var Checkbox = React34.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 = React33.forwardRef(({ mode: _mode, ...props }, ref) => {
76
+ var Switch = React34.forwardRef(({ mode: _mode, ...props }, ref) => {
77
77
  return /* @__PURE__ */ jsx(Switch$1, { ...props, ref });
78
78
  });
79
79
  Switch.displayName = "Switch";
@@ -429,6 +429,7 @@ function AppShell({
429
429
  collapsible = "icon",
430
430
  sidebarPosition = "viewport",
431
431
  side = "left",
432
+ contentClassName = "p-6",
432
433
  children
433
434
  } = {}) {
434
435
  const isContained = sidebarPosition === "contained";
@@ -453,7 +454,7 @@ function AppShell({
453
454
  ),
454
455
  /* @__PURE__ */ jsxs(SidebarInset, { className: isContained ? void 0 : "overflow-y-auto", children: [
455
456
  /* @__PURE__ */ jsx(ShellHeader, { pageTitle, headerStart, headerEnd }),
456
- children
457
+ /* @__PURE__ */ jsx("div", { className: contentClassName, children })
457
458
  ] })
458
459
  ]
459
460
  }
@@ -530,7 +531,7 @@ function DefaultForm({
530
531
  const isForgotPassword = mode === "forgot-password";
531
532
  const isResetPassword = mode === "reset-password";
532
533
  const isVerify = mode === "verify";
533
- const [code, setCode] = React33.useState("");
534
+ const [code, setCode] = React34.useState("");
534
535
  const hasPrefill = !!(defaultEmail || defaultPassword);
535
536
  const prefillStyle = (active) => active ? { animation: "auth-prefill 1.6s ease-out 0.35s 1 both" } : void 0;
536
537
  const copy = authCopy[mode];
@@ -690,10 +691,10 @@ function DataTable({
690
691
  emptyMessage = "No results.",
691
692
  className
692
693
  }) {
693
- const [sorting, setSorting] = React33.useState([]);
694
- const [rowSelection, setRowSelection] = React33.useState({});
695
- const [globalFilter, setGlobalFilter] = React33.useState("");
696
- const allColumns = React33.useMemo(
694
+ const [sorting, setSorting] = React34.useState([]);
695
+ const [rowSelection, setRowSelection] = React34.useState({});
696
+ const [globalFilter, setGlobalFilter] = React34.useState("");
697
+ const allColumns = React34.useMemo(
697
698
  () => selectable ? [selectColumn, ...columns] : columns,
698
699
  [selectable, columns]
699
700
  );
@@ -715,7 +716,7 @@ function DataTable({
715
716
  initialState: pageSize > 0 ? { pagination: { pageSize } } : void 0,
716
717
  enableRowSelection: selectable
717
718
  });
718
- React33.useEffect(() => {
719
+ React34.useEffect(() => {
719
720
  if (!onSelectionChange) return;
720
721
  onSelectionChange(table.getSelectedRowModel().rows.map((r) => r.original));
721
722
  }, [rowSelection]);
@@ -795,8 +796,8 @@ function DataTable({
795
796
  ] });
796
797
  }
797
798
  function InviteDialog({ roles, onInvite, onClose }) {
798
- const [email, setEmail] = React33.useState("");
799
- const [role, setRole] = React33.useState(roles[roles.length - 1] ?? roles[0]);
799
+ const [email, setEmail] = React34.useState("");
800
+ const [role, setRole] = React34.useState(roles[roles.length - 1] ?? roles[0]);
800
801
  return /* @__PURE__ */ jsx(DialogContent, { children: /* @__PURE__ */ jsxs(
801
802
  "form",
802
803
  {
@@ -840,8 +841,8 @@ function TeamMembersPanel({
840
841
  title = "Team members",
841
842
  description = "Manage who has access to this workspace."
842
843
  }) {
843
- const [inviteOpen, setInviteOpen] = React33.useState(false);
844
- const columns = React33.useMemo(() => [
844
+ const [inviteOpen, setInviteOpen] = React34.useState(false);
845
+ const columns = React34.useMemo(() => [
845
846
  {
846
847
  accessorKey: "name",
847
848
  header: "Name",
@@ -910,7 +911,7 @@ function BillingPanel({
910
911
  onUpdatePaymentMethod,
911
912
  className
912
913
  }) {
913
- const invoiceColumns = React33.useMemo(() => [
914
+ const invoiceColumns = React34.useMemo(() => [
914
915
  { accessorKey: "date", header: "Date", enableSorting: false },
915
916
  { accessorKey: "amount", header: "Amount", enableSorting: false },
916
917
  {
@@ -989,9 +990,9 @@ function OnboardingWizard({
989
990
  completeLabel = "Finish",
990
991
  className
991
992
  }) {
992
- const [internalStep, setInternalStep] = React33.useState(0);
993
- const [error, setError] = React33.useState(null);
994
- const [pending, setPending] = React33.useState(false);
993
+ const [internalStep, setInternalStep] = React34.useState(0);
994
+ const [error, setError] = React34.useState(null);
995
+ const [pending, setPending] = React34.useState(false);
995
996
  const index = stepProp ?? internalStep;
996
997
  const current = steps[index];
997
998
  const isLast = index === steps.length - 1;
@@ -1308,6 +1309,101 @@ function UpgradePrompt({
1308
1309
  }
1309
1310
  );
1310
1311
  }
1312
+ function UpdateBanner({
1313
+ currentVersion,
1314
+ fetchVersion,
1315
+ intervalMs = 5 * 60 * 1e3,
1316
+ forceShow = false,
1317
+ onRefresh,
1318
+ message = /* @__PURE__ */ jsxs(Fragment, { children: [
1319
+ /* @__PURE__ */ jsx("span", { className: "font-semibold", children: "App update available!" }),
1320
+ " Refresh to get the latest features and improvements."
1321
+ ] }),
1322
+ buttonLabel = "Refresh now",
1323
+ className
1324
+ }) {
1325
+ const [show, setShow] = React34.useState(forceShow);
1326
+ const [entered, setEntered] = React34.useState(false);
1327
+ const [refreshing, setRefreshing] = React34.useState(false);
1328
+ React34.useEffect(() => {
1329
+ if (forceShow) {
1330
+ setShow(true);
1331
+ return;
1332
+ }
1333
+ setShow(false);
1334
+ let cancelled = false;
1335
+ const check = async () => {
1336
+ try {
1337
+ const server = await fetchVersion();
1338
+ if (!cancelled && server.version && server.version !== currentVersion) {
1339
+ setShow(true);
1340
+ }
1341
+ } catch {
1342
+ }
1343
+ };
1344
+ void check();
1345
+ const id = setInterval(check, intervalMs);
1346
+ return () => {
1347
+ cancelled = true;
1348
+ clearInterval(id);
1349
+ };
1350
+ }, [currentVersion, fetchVersion, forceShow, intervalMs]);
1351
+ React34.useEffect(() => {
1352
+ if (!show) {
1353
+ setEntered(false);
1354
+ return;
1355
+ }
1356
+ const id = requestAnimationFrame(() => setEntered(true));
1357
+ return () => cancelAnimationFrame(id);
1358
+ }, [show]);
1359
+ const handleRefresh = () => {
1360
+ setRefreshing(true);
1361
+ setTimeout(() => {
1362
+ if (onRefresh) {
1363
+ onRefresh();
1364
+ setRefreshing(false);
1365
+ if (forceShow) setShow(false);
1366
+ } else {
1367
+ window.location.reload();
1368
+ }
1369
+ }, 400);
1370
+ };
1371
+ if (!show) return null;
1372
+ return /* @__PURE__ */ jsx("div", { className: "pointer-events-none fixed inset-x-0 top-4 z-50 flex justify-center px-4", children: /* @__PURE__ */ jsx(
1373
+ "div",
1374
+ {
1375
+ className: cn$1(
1376
+ "pointer-events-auto transition-all duration-500 ease-out",
1377
+ entered ? "translate-y-0 opacity-100" : "-translate-y-24 opacity-0"
1378
+ ),
1379
+ children: /* @__PURE__ */ jsx(
1380
+ Card$1,
1381
+ {
1382
+ className: cn$1(
1383
+ "max-w-3xl border-amber-300/60 bg-amber-50 dark:border-amber-700/60 dark:bg-amber-950",
1384
+ className
1385
+ ),
1386
+ children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-6 p-4", children: [
1387
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
1388
+ /* @__PURE__ */ jsx(Sparkles, { className: "size-5 shrink-0 text-amber-600 dark:text-amber-400", "aria-hidden": "true" }),
1389
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-amber-800 dark:text-amber-200", children: message })
1390
+ ] }),
1391
+ /* @__PURE__ */ jsx(
1392
+ Button$1,
1393
+ {
1394
+ onClick: handleRefresh,
1395
+ disabled: refreshing,
1396
+ size: "sm",
1397
+ className: "shrink-0 bg-amber-600 text-white hover:bg-amber-700 dark:bg-amber-600 dark:hover:bg-amber-700",
1398
+ children: refreshing ? /* @__PURE__ */ jsx(RefreshCw, { className: "size-4 animate-spin" }) : buttonLabel
1399
+ }
1400
+ )
1401
+ ] })
1402
+ }
1403
+ )
1404
+ }
1405
+ ) });
1406
+ }
1311
1407
  var translateMap = {
1312
1408
  up: "translate-y-6",
1313
1409
  down: "-translate-y-6",
@@ -1325,9 +1421,9 @@ function FadeIn({
1325
1421
  style,
1326
1422
  ...props
1327
1423
  }) {
1328
- const ref = React33.useRef(null);
1329
- const [visible, setVisible] = React33.useState(false);
1330
- React33.useEffect(() => {
1424
+ const ref = React34.useRef(null);
1425
+ const [visible, setVisible] = React34.useState(false);
1426
+ React34.useEffect(() => {
1331
1427
  const el = ref.current;
1332
1428
  if (!el) return;
1333
1429
  const observer = new IntersectionObserver(
@@ -1522,16 +1618,16 @@ function Carousel({
1522
1618
  className
1523
1619
  }) {
1524
1620
  const mode = useUIVariant();
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(() => {
1621
+ const trackRef = React34.useRef(null);
1622
+ const [canPrev, setCanPrev] = React34.useState(false);
1623
+ const [canNext, setCanNext] = React34.useState(true);
1624
+ const updateScrollState = React34.useCallback(() => {
1529
1625
  const track = trackRef.current;
1530
1626
  if (!track) return;
1531
1627
  setCanPrev(track.scrollLeft > 8);
1532
1628
  setCanNext(track.scrollLeft < track.scrollWidth - track.clientWidth - 8);
1533
1629
  }, []);
1534
- React33.useEffect(() => {
1630
+ React34.useEffect(() => {
1535
1631
  const track = trackRef.current;
1536
1632
  if (!track) return;
1537
1633
  updateScrollState();
@@ -1588,7 +1684,7 @@ function Carousel({
1588
1684
  role: "region",
1589
1685
  "aria-label": ariaLabel,
1590
1686
  className: "flex snap-x snap-mandatory gap-6 overflow-x-auto pb-4 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
1591
- children: React33.Children.map(
1687
+ children: React34.Children.map(
1592
1688
  children,
1593
1689
  (child) => child == null ? null : /* @__PURE__ */ jsx("div", { "data-carousel-item": true, className: cn$1("shrink-0 snap-start", itemClassName), children: child })
1594
1690
  )
@@ -1613,9 +1709,9 @@ function StaggerChildren({
1613
1709
  className,
1614
1710
  ...props
1615
1711
  }) {
1616
- const ref = React33.useRef(null);
1617
- const [visible, setVisible] = React33.useState(false);
1618
- React33.useEffect(() => {
1712
+ const ref = React34.useRef(null);
1713
+ const [visible, setVisible] = React34.useState(false);
1714
+ React34.useEffect(() => {
1619
1715
  const el = ref.current;
1620
1716
  if (!el) return;
1621
1717
  const observer = new IntersectionObserver(
@@ -1633,7 +1729,7 @@ function StaggerChildren({
1633
1729
  return () => observer.disconnect();
1634
1730
  }, [once]);
1635
1731
  const [tx, ty] = translateMap2[direction];
1636
- return /* @__PURE__ */ jsx("div", { ref, className: cn$1(className), ...props, children: React33.Children.map(children, (child, i) => /* @__PURE__ */ jsx(
1732
+ return /* @__PURE__ */ jsx("div", { ref, className: cn$1(className), ...props, children: React34.Children.map(children, (child, i) => /* @__PURE__ */ jsx(
1637
1733
  "div",
1638
1734
  {
1639
1735
  className: "h-full",
@@ -1775,7 +1871,7 @@ function StepsSection({
1775
1871
  /* @__PURE__ */ jsx("div", { className: "mt-12", children: resolvedGroups.map((group, groupIndex) => {
1776
1872
  const startNumber = nextNumber;
1777
1873
  nextNumber += group.steps.length;
1778
- return /* @__PURE__ */ jsxs(React33.Fragment, { children: [
1874
+ return /* @__PURE__ */ jsxs(React34.Fragment, { children: [
1779
1875
  /* @__PURE__ */ jsx("div", { className: cn$1(groupIndex > 0 && "mt-10"), children: /* @__PURE__ */ jsx(TimelineGroup, { steps: group.steps, startNumber, fadeIn: groupIndex > 0 }) }),
1780
1876
  group.after && /* @__PURE__ */ jsx("div", { className: "mt-16", children: group.after })
1781
1877
  ] }, groupIndex);
@@ -1945,9 +2041,9 @@ function FeatureMarqueeSection({
1945
2041
  ] });
1946
2042
  }
1947
2043
  function useIntersectionObserver(options) {
1948
- const ref = React33.useRef(null);
1949
- const [isIntersecting, setIsIntersecting] = React33.useState(false);
1950
- React33.useEffect(() => {
2044
+ const ref = React34.useRef(null);
2045
+ const [isIntersecting, setIsIntersecting] = React34.useState(false);
2046
+ React34.useEffect(() => {
1951
2047
  const el = ref.current;
1952
2048
  if (!el) return;
1953
2049
  const observer = new IntersectionObserver(([entry]) => {
@@ -1969,8 +2065,8 @@ function ShowcaseCta({
1969
2065
  sectionClasses
1970
2066
  }) {
1971
2067
  const [ref, intersecting] = useIntersectionObserver({ threshold: 0.15 });
1972
- const [visible, setVisible] = React33.useState(false);
1973
- React33.useEffect(() => {
2068
+ const [visible, setVisible] = React34.useState(false);
2069
+ React34.useEffect(() => {
1974
2070
  if (intersecting) setVisible(true);
1975
2071
  }, [intersecting]);
1976
2072
  return /* @__PURE__ */ jsxs(
@@ -2147,8 +2243,8 @@ function CountdownTimer({
2147
2243
  className,
2148
2244
  compact = false
2149
2245
  }) {
2150
- const [timeLeft, setTimeLeft] = React33.useState(() => getTimeLeft(deadline));
2151
- React33.useEffect(() => {
2246
+ const [timeLeft, setTimeLeft] = React34.useState(() => getTimeLeft(deadline));
2247
+ React34.useEffect(() => {
2152
2248
  setTimeLeft(getTimeLeft(deadline));
2153
2249
  const id = setInterval(() => setTimeLeft(getTimeLeft(deadline)), 1e3);
2154
2250
  return () => clearInterval(id);
@@ -2174,7 +2270,7 @@ function CountdownTimer({
2174
2270
  ];
2175
2271
  return /* @__PURE__ */ jsxs("div", { className: cn$1("flex items-center justify-center gap-2 text-sm", className), children: [
2176
2272
  /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: label }),
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: [
2273
+ /* @__PURE__ */ jsx("span", { className: "flex items-center gap-1 font-mono font-semibold tabular-nums", children: units.map(({ value, unit }, i) => /* @__PURE__ */ jsxs(React34.Fragment, { children: [
2178
2274
  /* @__PURE__ */ jsxs("span", { children: [
2179
2275
  String(value).padStart(2, "0"),
2180
2276
  /* @__PURE__ */ jsx("span", { className: "font-normal text-muted-foreground", children: unit })
@@ -2199,7 +2295,7 @@ function PricingSection({
2199
2295
  highlightedBadgeLabel = "Founding member",
2200
2296
  renderPlanFooter
2201
2297
  }) {
2202
- const [annual, setAnnual] = React33.useState(false);
2298
+ const [annual, setAnnual] = React34.useState(false);
2203
2299
  const isOneTime = mode === "one-time";
2204
2300
  const uiMode = useUIVariant();
2205
2301
  const sectionClasses = cn$1(
@@ -2468,10 +2564,10 @@ function CountUp({
2468
2564
  className,
2469
2565
  ...props
2470
2566
  }) {
2471
- const ref = React33.useRef(null);
2472
- const [value, setValue] = React33.useState(from);
2473
- const hasStarted = React33.useRef(false);
2474
- React33.useEffect(() => {
2567
+ const ref = React34.useRef(null);
2568
+ const [value, setValue] = React34.useState(from);
2569
+ const hasStarted = React34.useRef(false);
2570
+ React34.useEffect(() => {
2475
2571
  const el = ref.current;
2476
2572
  if (!el) return;
2477
2573
  const observer = new IntersectionObserver(
@@ -2564,8 +2660,8 @@ function NewsletterSection({
2564
2660
  successDescription = defaults.successDescription,
2565
2661
  onSubscribe
2566
2662
  } = {}) {
2567
- const [email, setEmail] = React33.useState("");
2568
- const [submitted, setSubmitted] = React33.useState(false);
2663
+ const [email, setEmail] = React34.useState("");
2664
+ const [submitted, setSubmitted] = React34.useState(false);
2569
2665
  const mode = useUIVariant();
2570
2666
  const sectionClasses = cn$1(
2571
2667
  "overflow-hidden bg-card",
@@ -2656,7 +2752,7 @@ function ContactSection({
2656
2752
  sendAnotherLabel = defaults2.sendAnotherLabel,
2657
2753
  onSubmit
2658
2754
  } = {}) {
2659
- const [submitted, setSubmitted] = React33.useState(false);
2755
+ const [submitted, setSubmitted] = React34.useState(false);
2660
2756
  const mode = useUIVariant();
2661
2757
  const sectionClasses = cn$1(
2662
2758
  "overflow-hidden bg-card",
@@ -2954,7 +3050,7 @@ function Navbar({
2954
3050
  controls,
2955
3051
  renderLink = defaultRenderLink7
2956
3052
  }) {
2957
- const [open, setOpen] = React33.useState(false);
3053
+ const [open, setOpen] = React34.useState(false);
2958
3054
  const brandHref = brand.href ?? "/";
2959
3055
  const hasRightContent = controls?.length || cta?.primary || cta?.secondary;
2960
3056
  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: [
@@ -2971,7 +3067,7 @@ function Navbar({
2971
3067
  children: link.label
2972
3068
  }) }, link.label)) }),
2973
3069
  hasRightContent && /* @__PURE__ */ jsxs("div", { className: "hidden items-center justify-end gap-2 md:flex", children: [
2974
- controls?.map((control, i) => /* @__PURE__ */ jsx(React33.Fragment, { children: control }, i)),
3070
+ controls?.map((control, i) => /* @__PURE__ */ jsx(React34.Fragment, { children: control }, i)),
2975
3071
  (cta?.secondary || cta?.primary) && controls?.length ? /* @__PURE__ */ jsx("div", { className: "mx-1 h-4 w-px bg-border" }) : null,
2976
3072
  cta?.secondary && renderLink({
2977
3073
  href: cta.secondary.href,
@@ -2995,7 +3091,7 @@ function Navbar({
2995
3091
  /* @__PURE__ */ jsx("span", { children: brand.name })
2996
3092
  ] })
2997
3093
  }) }) }),
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,
3094
+ controls?.length ? /* @__PURE__ */ jsx("div", { className: "mb-4 flex w-full items-center justify-between gap-1", children: controls.map((control, i) => /* @__PURE__ */ jsx(React34.Fragment, { children: control }, i)) }) : null,
2999
3095
  /* @__PURE__ */ jsx(Separator, {}),
3000
3096
  /* @__PURE__ */ jsx("nav", { className: "mt-4 flex flex-col gap-1", children: navLinks.map((link) => /* @__PURE__ */ jsx("span", { onClick: () => setOpen(false), children: renderLink({
3001
3097
  href: link.href,
@@ -3144,7 +3240,7 @@ function LogoStrip({
3144
3240
  ] });
3145
3241
  }
3146
3242
  function GridUnderlay({ variant, size = 24, className, ...props }) {
3147
- const id = React33.useId();
3243
+ const id = React34.useId();
3148
3244
  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: [
3149
3245
  /* @__PURE__ */ jsx("line", { x1: size / 2, y1: 0, x2: size / 2, y2: size, stroke: "currentColor", strokeWidth: 0.5 }),
3150
3246
  /* @__PURE__ */ jsx("line", { x1: 0, y1: size / 2, x2: size, y2: size / 2, stroke: "currentColor", strokeWidth: 0.5 })
@@ -3172,9 +3268,9 @@ function GlowUnderlay({
3172
3268
  style,
3173
3269
  ...props
3174
3270
  }) {
3175
- const [pos, setPos] = React33.useState({ x: "50%", y: "50%" });
3176
- const containerRef = React33.useRef(null);
3177
- React33.useEffect(() => {
3271
+ const [pos, setPos] = React34.useState({ x: "50%", y: "50%" });
3272
+ const containerRef = React34.useRef(null);
3273
+ React34.useEffect(() => {
3178
3274
  if (!followCursor) return;
3179
3275
  const handleMouseMove = (e) => {
3180
3276
  const el = containerRef.current;
@@ -3313,8 +3409,8 @@ function PageTransition({
3313
3409
  style,
3314
3410
  ...props
3315
3411
  }) {
3316
- const [mounted, setMounted] = React33.useState(false);
3317
- React33.useEffect(() => {
3412
+ const [mounted, setMounted] = React34.useState(false);
3413
+ React34.useEffect(() => {
3318
3414
  const id = requestAnimationFrame(() => setMounted(true));
3319
3415
  return () => cancelAnimationFrame(id);
3320
3416
  }, []);
@@ -3389,7 +3485,7 @@ function Sortable({
3389
3485
  if (oldIndex === -1 || newIndex === -1) return;
3390
3486
  onReorder(arrayMove(items, oldIndex, newIndex));
3391
3487
  };
3392
- const childArray = React33.Children.toArray(children);
3488
+ const childArray = React34.Children.toArray(children);
3393
3489
  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(
3394
3490
  (child, i) => items[i] === void 0 ? null : /* @__PURE__ */ jsx(SortableItem, { id: items[i], disabled, className: itemClassName, children: child }, items[i])
3395
3491
  ) }) }) });
@@ -3401,8 +3497,8 @@ function Spotlight({
3401
3497
  triggerClassName,
3402
3498
  shortcut = "\u2318K"
3403
3499
  }) {
3404
- const [open, setOpen] = React33.useState(false);
3405
- React33.useEffect(() => {
3500
+ const [open, setOpen] = React34.useState(false);
3501
+ React34.useEffect(() => {
3406
3502
  const down = (e) => {
3407
3503
  if (e.key === "k" && (e.metaKey || e.ctrlKey)) {
3408
3504
  e.preventDefault();
@@ -3432,7 +3528,7 @@ function Spotlight({
3432
3528
  /* @__PURE__ */ jsx(CommandInput, { placeholder }),
3433
3529
  /* @__PURE__ */ jsxs(CommandList, { children: [
3434
3530
  /* @__PURE__ */ jsx(CommandEmpty, { children: "No results found." }),
3435
- groups.map((group, i) => /* @__PURE__ */ jsxs(React33.Fragment, { children: [
3531
+ groups.map((group, i) => /* @__PURE__ */ jsxs(React34.Fragment, { children: [
3436
3532
  i > 0 && /* @__PURE__ */ jsx(CommandSeparator, {}),
3437
3533
  /* @__PURE__ */ jsx(CommandGroup, { heading: group.heading, children: group.items.map((item) => /* @__PURE__ */ jsxs(
3438
3534
  CommandItem,
@@ -3457,8 +3553,8 @@ function Spotlight({
3457
3553
  var BASE = 40;
3458
3554
  var MAGNIFY_RADIUS = 80;
3459
3555
  function Dock({ items, iconSize = BASE, magnification = 1.7, className, ...props }) {
3460
- const [mouseX, setMouseX] = React33.useState(null);
3461
- const containerRef = React33.useRef(null);
3556
+ const [mouseX, setMouseX] = React34.useState(null);
3557
+ const containerRef = React34.useRef(null);
3462
3558
  function getScale(index) {
3463
3559
  if (mouseX === null || !containerRef.current) return 1;
3464
3560
  const container = containerRef.current;
@@ -3557,7 +3653,7 @@ function ConfirmDialog({ isOpen, options, handleConfirm, handleCancel, destructi
3557
3653
  ] }) });
3558
3654
  }
3559
3655
  function RegisterHotkeys({ hotkeys }) {
3560
- React33.useEffect(() => {
3656
+ React34.useEffect(() => {
3561
3657
  const handleKeyDown = (event) => {
3562
3658
  for (const hotkey of hotkeys) {
3563
3659
  const matches = event.key.toLowerCase() === hotkey.key.toLowerCase() && !!event.ctrlKey === !!hotkey.ctrl && !!event.metaKey === !!hotkey.meta && !!event.shiftKey === !!hotkey.shift && !!event.altKey === !!hotkey.alt;
@@ -3574,10 +3670,10 @@ function RegisterHotkeys({ hotkeys }) {
3574
3670
  return null;
3575
3671
  }
3576
3672
  function useControlledOpen(defaultOpen = false) {
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), []);
3673
+ const [isOpen, setIsOpen] = React34.useState(defaultOpen);
3674
+ const open = React34.useCallback(() => setIsOpen(true), []);
3675
+ const close = React34.useCallback(() => setIsOpen(false), []);
3676
+ const toggle = React34.useCallback(() => setIsOpen((prev) => !prev), []);
3581
3677
  return { isOpen, open, close, toggle, setIsOpen };
3582
3678
  }
3583
3679
  function CommandMenu({
@@ -3590,7 +3686,7 @@ function CommandMenu({
3590
3686
  }) {
3591
3687
  const internal = useControlledOpen(false);
3592
3688
  const isOpen = openProp ?? internal.isOpen;
3593
- const setOpen = React33.useCallback(
3689
+ const setOpen = React34.useCallback(
3594
3690
  (next) => {
3595
3691
  if (openProp === void 0) internal.setIsOpen(next);
3596
3692
  onOpenChange?.(next);
@@ -3615,7 +3711,7 @@ function CommandMenu({
3615
3711
  /* @__PURE__ */ jsx(CommandInput, { placeholder }),
3616
3712
  /* @__PURE__ */ jsxs(CommandList, { children: [
3617
3713
  /* @__PURE__ */ jsx(CommandEmpty, { children: emptyMessage }),
3618
- groups.map((group, i) => /* @__PURE__ */ jsxs(React33.Fragment, { children: [
3714
+ groups.map((group, i) => /* @__PURE__ */ jsxs(React34.Fragment, { children: [
3619
3715
  i > 0 && /* @__PURE__ */ jsx(CommandSeparator, {}),
3620
3716
  /* @__PURE__ */ jsx(CommandGroup, { heading: group.heading, children: group.items.map((item) => /* @__PURE__ */ jsxs(
3621
3717
  CommandItem,
@@ -3807,20 +3903,20 @@ function FileUpload({
3807
3903
  hint,
3808
3904
  className
3809
3905
  }) {
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);
3906
+ const [internalFiles, setInternalFiles] = React34.useState(defaultFiles ?? []);
3907
+ const [isDragging, setIsDragging] = React34.useState(false);
3908
+ const [validationError, setValidationError] = React34.useState(null);
3909
+ const inputRef = React34.useRef(null);
3910
+ const dragDepth = React34.useRef(0);
3815
3911
  const files = filesProp ?? internalFiles;
3816
- const setFiles = React33.useCallback(
3912
+ const setFiles = React34.useCallback(
3817
3913
  (next) => {
3818
3914
  if (!filesProp) setInternalFiles(next);
3819
3915
  onFilesChange?.(next);
3820
3916
  },
3821
3917
  [filesProp, onFilesChange]
3822
3918
  );
3823
- const acceptList = React33.useMemo(
3919
+ const acceptList = React34.useMemo(
3824
3920
  () => accept?.split(",").map((a) => a.trim().toLowerCase()).filter(Boolean) ?? [],
3825
3921
  [accept]
3826
3922
  );
@@ -4487,7 +4583,7 @@ function PageHeader({
4487
4583
  return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-1 pb-6", className), children: [
4488
4584
  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) => {
4489
4585
  const isLast = i === breadcrumbs.length - 1;
4490
- return /* @__PURE__ */ jsxs(React33.Fragment, { children: [
4586
+ return /* @__PURE__ */ jsxs(React34.Fragment, { children: [
4491
4587
  i > 0 && /* @__PURE__ */ jsx(ChevronRight, { className: "size-3.5 shrink-0" }),
4492
4588
  isLast || !crumb.href ? /* @__PURE__ */ jsx("span", { className: cn(isLast && "text-foreground font-medium"), children: crumb.label }) : renderLink({
4493
4589
  href: crumb.href,
@@ -4523,7 +4619,7 @@ function PageHeader({
4523
4619
  ] });
4524
4620
  }
4525
4621
  function Suspensed({ children, fallback }) {
4526
- return /* @__PURE__ */ jsx(React33.Suspense, { fallback: fallback ?? /* @__PURE__ */ jsx(Spinner, {}), children });
4622
+ return /* @__PURE__ */ jsx(React34.Suspense, { fallback: fallback ?? /* @__PURE__ */ jsx(Spinner, {}), children });
4527
4623
  }
4528
4624
  function getInitialTheme() {
4529
4625
  if (typeof document === "undefined") return "dark";
@@ -4531,7 +4627,7 @@ function getInitialTheme() {
4531
4627
  return stored ?? (document.documentElement.classList.contains("dark") ? "dark" : "light");
4532
4628
  }
4533
4629
  function ThemeSwitchMinimal() {
4534
- const [theme, setThemeState] = React33.useState(getInitialTheme);
4630
+ const [theme, setThemeState] = React34.useState(getInitialTheme);
4535
4631
  const toggle = () => {
4536
4632
  const next = theme === "dark" ? "light" : "dark";
4537
4633
  setThemeState(next);
@@ -4657,9 +4753,9 @@ function getInitialColorName() {
4657
4753
  return localStorage.getItem(STORAGE_KEY) ?? "emerald";
4658
4754
  }
4659
4755
  function BrandColorSwitchMinimal() {
4660
- const [active, setActive] = React33.useState(getInitialColorName);
4661
- const [open, setOpen] = React33.useState(false);
4662
- React33.useEffect(() => {
4756
+ const [active, setActive] = React34.useState(getInitialColorName);
4757
+ const [open, setOpen] = React34.useState(false);
4758
+ React34.useEffect(() => {
4663
4759
  const saved = localStorage.getItem(STORAGE_KEY) ?? "emerald";
4664
4760
  const color = BRAND_COLORS.find((c) => c.name === saved);
4665
4761
  if (color) applyColor(color);
@@ -4720,7 +4816,7 @@ function BrandColorSwitchMinimal() {
4720
4816
  ] });
4721
4817
  }
4722
4818
  function ThemeColorUpdater({ colorTheme }) {
4723
- React33.useEffect(() => {
4819
+ React34.useEffect(() => {
4724
4820
  if (colorTheme) {
4725
4821
  document.documentElement.setAttribute("data-theme", colorTheme);
4726
4822
  } else {
@@ -4730,7 +4826,7 @@ function ThemeColorUpdater({ colorTheme }) {
4730
4826
  return null;
4731
4827
  }
4732
4828
  function VersionBanner({ version, message, className, onDismiss }) {
4733
- const [dismissed, setDismissed] = React33.useState(false);
4829
+ const [dismissed, setDismissed] = React34.useState(false);
4734
4830
  if (dismissed) return null;
4735
4831
  return /* @__PURE__ */ jsxs("div", { className: cn("flex items-center justify-between gap-4 bg-primary/10 px-4 py-2 text-sm", className), children: [
4736
4832
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
@@ -4987,29 +5083,29 @@ function useMounted() {
4987
5083
  return mounted;
4988
5084
  }
4989
5085
  function useConfirm() {
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 = {}) => {
5086
+ const [isOpen, setIsOpen] = React34.useState(false);
5087
+ const [options, setOptions] = React34.useState({});
5088
+ const resolveRef = React34.useRef(null);
5089
+ const confirm = React34.useCallback((opts = {}) => {
4994
5090
  setOptions(opts);
4995
5091
  setIsOpen(true);
4996
5092
  return new Promise((resolve) => {
4997
5093
  resolveRef.current = resolve;
4998
5094
  });
4999
5095
  }, []);
5000
- const handleConfirm = React33.useCallback(() => {
5096
+ const handleConfirm = React34.useCallback(() => {
5001
5097
  resolveRef.current?.(true);
5002
5098
  setIsOpen(false);
5003
5099
  }, []);
5004
- const handleCancel = React33.useCallback(() => {
5100
+ const handleCancel = React34.useCallback(() => {
5005
5101
  resolveRef.current?.(false);
5006
5102
  setIsOpen(false);
5007
5103
  }, []);
5008
5104
  return { confirm, isOpen, options, handleConfirm, handleCancel };
5009
5105
  }
5010
5106
  function useScrolledPast(threshold) {
5011
- const [scrolledPast, setScrolledPast] = React33.useState(false);
5012
- React33.useEffect(() => {
5107
+ const [scrolledPast, setScrolledPast] = React34.useState(false);
5108
+ React34.useEffect(() => {
5013
5109
  const handleScroll = () => {
5014
5110
  setScrolledPast(window.scrollY > threshold);
5015
5111
  };
@@ -5020,28 +5116,28 @@ function useScrolledPast(threshold) {
5020
5116
  return scrolledPast;
5021
5117
  }
5022
5118
  function useCopyToClipboard() {
5023
- const [copied, setCopied] = React33.useState(false);
5024
- const timeoutRef = React33.useRef(void 0);
5025
- const copy = React33.useCallback((text) => {
5119
+ const [copied, setCopied] = React34.useState(false);
5120
+ const timeoutRef = React34.useRef(void 0);
5121
+ const copy = React34.useCallback((text) => {
5026
5122
  navigator.clipboard.writeText(text).then(() => {
5027
5123
  setCopied(true);
5028
5124
  clearTimeout(timeoutRef.current);
5029
5125
  timeoutRef.current = setTimeout(() => setCopied(false), 2e3);
5030
5126
  });
5031
5127
  }, []);
5032
- React33.useEffect(() => () => clearTimeout(timeoutRef.current), []);
5128
+ React34.useEffect(() => () => clearTimeout(timeoutRef.current), []);
5033
5129
  return [copied, copy];
5034
5130
  }
5035
5131
  function useDebounce(value, delay) {
5036
- const [debounced, setDebounced] = React33.useState(value);
5037
- React33.useEffect(() => {
5132
+ const [debounced, setDebounced] = React34.useState(value);
5133
+ React34.useEffect(() => {
5038
5134
  const timer = setTimeout(() => setDebounced(value), delay);
5039
5135
  return () => clearTimeout(timer);
5040
5136
  }, [value, delay]);
5041
5137
  return debounced;
5042
5138
  }
5043
5139
  function useLocalStorage(key, initialValue) {
5044
- const [storedValue, setStoredValue] = React33.useState(() => {
5140
+ const [storedValue, setStoredValue] = React34.useState(() => {
5045
5141
  if (typeof window === "undefined") return initialValue;
5046
5142
  try {
5047
5143
  const item = window.localStorage.getItem(key);
@@ -5050,7 +5146,7 @@ function useLocalStorage(key, initialValue) {
5050
5146
  return initialValue;
5051
5147
  }
5052
5148
  });
5053
- const setValue = React33.useCallback(
5149
+ const setValue = React34.useCallback(
5054
5150
  (value) => {
5055
5151
  try {
5056
5152
  setStoredValue(value);
@@ -5065,11 +5161,11 @@ function useLocalStorage(key, initialValue) {
5065
5161
  return [storedValue, setValue];
5066
5162
  }
5067
5163
  function useMediaQuery(query) {
5068
- const [matches, setMatches] = React33.useState(() => {
5164
+ const [matches, setMatches] = React34.useState(() => {
5069
5165
  if (typeof window === "undefined") return false;
5070
5166
  return window.matchMedia(query).matches;
5071
5167
  });
5072
- React33.useEffect(() => {
5168
+ React34.useEffect(() => {
5073
5169
  if (typeof window === "undefined") return;
5074
5170
  const mql = window.matchMedia(query);
5075
5171
  setMatches(mql.matches);
@@ -5080,18 +5176,18 @@ function useMediaQuery(query) {
5080
5176
  return matches;
5081
5177
  }
5082
5178
  function usePagination(total, pageSize) {
5083
- const [page, setPage] = React33.useState(1);
5179
+ const [page, setPage] = React34.useState(1);
5084
5180
  const totalPages = Math.max(1, Math.ceil(total / pageSize));
5085
5181
  const offset = (page - 1) * pageSize;
5086
- const goTo = React33.useCallback(
5182
+ const goTo = React34.useCallback(
5087
5183
  (p) => setPage(Math.min(Math.max(1, p), totalPages)),
5088
5184
  [totalPages]
5089
5185
  );
5090
- const next = React33.useCallback(() => goTo(page + 1), [page, goTo]);
5091
- const prev = React33.useCallback(() => goTo(page - 1), [page, goTo]);
5186
+ const next = React34.useCallback(() => goTo(page + 1), [page, goTo]);
5187
+ const prev = React34.useCallback(() => goTo(page - 1), [page, goTo]);
5092
5188
  return { page, pageSize, totalPages, offset, hasPrev: page > 1, hasNext: page < totalPages, goTo, next, prev };
5093
5189
  }
5094
5190
 
5095
- export { ActivityFeed, AnimatedPill, AppContent, AppGrid, AppGridCell, AppScreen, AppShell, AuthSection, Badge, BillingPanel, BrandColorSwitchMinimal, Button, Card, Carousel, ChangelogCard, ChangelogList, Chart, Checkbox, CommandMenu, ComparisonSection, ConfirmDialog, ContactSection, ContextMenu, CountUp, CountdownTimer, CtaSection, DataTable, DevBanner, Dock, EmptyState, ErrorPage, FadeIn, FaqSection, FeatureCard, FeatureMarqueeSection, FeaturesSection, FileUpload, FlowBracket, FlowConnector, Footer, FullPageSpinner, GlassCard, Grid, GridItem, GroupedFeaturesSection, HeroSection, ImageCard, Input, LogoStrip, ModeSwitchMinimal, Navbar, NewsletterSection, NotificationToast, NotificationsPopover, OlwibaUIProvider, OnboardingWizard, Overlay, PageHeader, PageTransition, PhoneFrame, PostCard, PostList, PricingCard, PricingSection, PublicPageFrame, QualificationSection, RegisterHotkeys, RootErrorFallback, Section, SectionTitle, SettingsSection, Sortable, Spotlight, Stack, StaggerChildren, StatCard, StatsSection, StepsSection, Suspensed, Switch, TeamMembersPanel, TeamSection, TechStackSection, TestimonialCard, TestimonialsSection, Textarea, ThemeColorUpdater, ThemeSwitchMinimal, Underlay, UpgradePrompt, VersionBanner, marketingSectionSpacing, notify, useConfirm, useControlledOpen, useCopyToClipboard, useDebounce, useIntersectionObserver, useLocalStorage, useMediaQuery, useMounted, useOlwibaUI, usePagination, useScrolledPast, useUIMode };
5191
+ export { ActivityFeed, AnimatedPill, AppContent, AppGrid, AppGridCell, AppScreen, AppShell, AuthSection, Badge, BillingPanel, BrandColorSwitchMinimal, Button, Card, Carousel, ChangelogCard, ChangelogList, Chart, Checkbox, CommandMenu, ComparisonSection, ConfirmDialog, ContactSection, ContextMenu, CountUp, CountdownTimer, CtaSection, DataTable, DevBanner, Dock, EmptyState, ErrorPage, FadeIn, FaqSection, FeatureCard, FeatureMarqueeSection, FeaturesSection, FileUpload, FlowBracket, FlowConnector, Footer, FullPageSpinner, GlassCard, Grid, GridItem, GroupedFeaturesSection, HeroSection, ImageCard, Input, LogoStrip, ModeSwitchMinimal, Navbar, NewsletterSection, NotificationToast, NotificationsPopover, OlwibaUIProvider, OnboardingWizard, Overlay, PageHeader, PageTransition, PhoneFrame, PostCard, PostList, PricingCard, PricingSection, PublicPageFrame, QualificationSection, RegisterHotkeys, RootErrorFallback, Section, SectionTitle, SettingsSection, Sortable, Spotlight, Stack, StaggerChildren, StatCard, StatsSection, StepsSection, Suspensed, Switch, TeamMembersPanel, TeamSection, TechStackSection, TestimonialCard, TestimonialsSection, Textarea, ThemeColorUpdater, ThemeSwitchMinimal, Underlay, UpdateBanner, UpgradePrompt, VersionBanner, marketingSectionSpacing, notify, useConfirm, useControlledOpen, useCopyToClipboard, useDebounce, useIntersectionObserver, useLocalStorage, useMediaQuery, useMounted, useOlwibaUI, usePagination, useScrolledPast, useUIMode };
5096
5192
  //# sourceMappingURL=index.js.map
5097
5193
  //# sourceMappingURL=index.js.map