@olwiba/ui 0.2.10 → 0.2.12

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 React35 from 'react';
3
+ import * as React20 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 = React35.createContext({
16
+ var OlwibaUIContext = React20.createContext({
17
17
  isMobile: false,
18
18
  mode: "default",
19
19
  setMode: () => {
@@ -22,17 +22,17 @@ var OlwibaUIContext = React35.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] = React35.useState(initialMode);
25
+ const [mode, setMode] = React20.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 React35.useContext(OlwibaUIContext);
30
+ return React20.useContext(OlwibaUIContext);
31
31
  }
32
32
  function useUIMode() {
33
- return React35.useContext(OlwibaUIContext).mode;
33
+ return React20.useContext(OlwibaUIContext).mode;
34
34
  }
35
- var Button = React35.forwardRef(
35
+ var Button = React20.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 = React35.forwardRef(
40
40
  }
41
41
  );
42
42
  Button.displayName = "Button";
43
- var Card = React35.forwardRef(
43
+ var Card = React20.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 = React35.forwardRef(
54
+ var Input = React20.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 = React35.forwardRef(
59
59
  }
60
60
  );
61
61
  Input.displayName = "Input";
62
- var Textarea = React35.forwardRef(
62
+ var Textarea = React20.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 = React35.forwardRef(
67
67
  }
68
68
  );
69
69
  Textarea.displayName = "Textarea";
70
- var Checkbox = React35.forwardRef(({ mode, ...props }, ref) => {
70
+ var Checkbox = React20.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 = React35.forwardRef(({ mode: _mode, ...props }, ref) => {
76
+ var Switch = React20.forwardRef(({ mode: _mode, ...props }, ref) => {
77
77
  return /* @__PURE__ */ jsx(Switch$1, { ...props, ref });
78
78
  });
79
79
  Switch.displayName = "Switch";
@@ -261,6 +261,7 @@ function PublicPageFrame({
261
261
  }) {
262
262
  return /* @__PURE__ */ jsx("div", { className: cn("min-h-screen", surfaceMap[surface], className), ...props, children: /* @__PURE__ */ jsx("div", { className: cn("flex flex-col", spacingMap2[spacing], maxWidthMap2[maxWidth]), children }) });
263
263
  }
264
+ var RAIL_SQUARE = "group-data-[collapsible=icon]:!size-8 group-data-[collapsible=icon]:!min-w-8 group-data-[collapsible=icon]:!max-w-8 group-data-[collapsible=icon]:!p-0 group-data-[collapsible=icon]:transition-[width,height]";
264
265
  function NavUser({ user }) {
265
266
  const { isMobile } = useSidebar();
266
267
  const uiMode = useUIMode();
@@ -271,7 +272,11 @@ function NavUser({ user }) {
271
272
  SidebarMenuButton,
272
273
  {
273
274
  size: "lg",
274
- className: "data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground group-data-[collapsible=icon]:!size-8 group-data-[collapsible=icon]:!min-w-8 group-data-[collapsible=icon]:!max-w-8 group-data-[collapsible=icon]:!p-0",
275
+ tooltip: user.name ?? user.email,
276
+ className: cn$1(
277
+ "data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground",
278
+ RAIL_SQUARE
279
+ ),
275
280
  children: [
276
281
  /* @__PURE__ */ jsxs(Avatar, { mode: avatarMode, size: "sm", className: "grayscale", children: [
277
282
  user.avatar && /* @__PURE__ */ jsx(AvatarImage, { src: user.avatar, alt: user.name }),
@@ -345,8 +350,7 @@ function ShellSidebar({
345
350
  {
346
351
  asChild: true,
347
352
  size: "lg",
348
- tooltip: typeof brand.name === "string" ? brand.name : void 0,
349
- className: "group-data-[collapsible=icon]:!size-8 group-data-[collapsible=icon]:!min-w-8 group-data-[collapsible=icon]:!max-w-8 group-data-[collapsible=icon]:!p-0",
353
+ className: RAIL_SQUARE,
350
354
  children: renderLink({
351
355
  href: brand.href ?? "#",
352
356
  children: /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -469,10 +473,16 @@ function AppShell({
469
473
  }
470
474
  var defaultRenderLink2 = ({ href, children, className }) => /* @__PURE__ */ jsx("a", { href, className, children });
471
475
  function CenteredAuth({ children, brand, className }) {
472
- return /* @__PURE__ */ jsxs("section", { className: cn$1("flex min-h-screen flex-col justify-center bg-background py-12 px-4 sm:px-6 lg:px-8", className), children: [
473
- brand && /* @__PURE__ */ jsx("div", { className: "mx-auto w-full max-w-md text-center mb-8", children: brand }),
474
- /* @__PURE__ */ jsx("div", { className: "mx-auto w-full max-w-md", children })
475
- ] });
476
+ return (
477
+ // `min-h-dvh`, not `min-h-screen`: on mobile `100vh` is the viewport with
478
+ // the browser chrome *retracted*, so a screen-height box is always taller
479
+ // than what you can actually see, and it resizes under you as the URL bar
480
+ // hides and shows.
481
+ /* @__PURE__ */ jsx("section", { className: cn$1("flex min-h-dvh flex-col bg-background px-4 py-10 sm:px-6 sm:py-12 lg:px-8", className), children: /* @__PURE__ */ jsxs("div", { className: "mx-auto w-full max-w-md sm:my-auto", children: [
482
+ brand && /* @__PURE__ */ jsx("div", { className: "mb-8 text-center", children: brand }),
483
+ children
484
+ ] }) })
485
+ );
476
486
  }
477
487
  function SplitAuth({ children, panel }) {
478
488
  const defaultPanel = /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-6", children: [
@@ -534,7 +544,7 @@ function DefaultForm({
534
544
  const isForgotPassword = mode === "forgot-password";
535
545
  const isResetPassword = mode === "reset-password";
536
546
  const isVerify = mode === "verify";
537
- const [code, setCode] = React35.useState("");
547
+ const [code, setCode] = React20.useState("");
538
548
  const hasPrefill = !!(defaultEmail || defaultPassword);
539
549
  const prefillStyle = (active) => active ? { animation: "auth-prefill 1.6s ease-out 0.35s 1 both" } : void 0;
540
550
  const copy = authCopy[mode];
@@ -694,10 +704,10 @@ function DataTable({
694
704
  emptyMessage = "No results.",
695
705
  className
696
706
  }) {
697
- const [sorting, setSorting] = React35.useState([]);
698
- const [rowSelection, setRowSelection] = React35.useState({});
699
- const [globalFilter, setGlobalFilter] = React35.useState("");
700
- const allColumns = React35.useMemo(
707
+ const [sorting, setSorting] = React20.useState([]);
708
+ const [rowSelection, setRowSelection] = React20.useState({});
709
+ const [globalFilter, setGlobalFilter] = React20.useState("");
710
+ const allColumns = React20.useMemo(
701
711
  () => selectable ? [selectColumn, ...columns] : columns,
702
712
  [selectable, columns]
703
713
  );
@@ -719,7 +729,7 @@ function DataTable({
719
729
  initialState: pageSize > 0 ? { pagination: { pageSize } } : void 0,
720
730
  enableRowSelection: selectable
721
731
  });
722
- React35.useEffect(() => {
732
+ React20.useEffect(() => {
723
733
  if (!onSelectionChange) return;
724
734
  onSelectionChange(table.getSelectedRowModel().rows.map((r) => r.original));
725
735
  }, [rowSelection]);
@@ -799,8 +809,8 @@ function DataTable({
799
809
  ] });
800
810
  }
801
811
  function InviteDialog({ roles, onInvite, onClose }) {
802
- const [email, setEmail] = React35.useState("");
803
- const [role, setRole] = React35.useState(roles[roles.length - 1] ?? roles[0]);
812
+ const [email, setEmail] = React20.useState("");
813
+ const [role, setRole] = React20.useState(roles[roles.length - 1] ?? roles[0]);
804
814
  return /* @__PURE__ */ jsx(DialogContent, { children: /* @__PURE__ */ jsxs(
805
815
  "form",
806
816
  {
@@ -844,8 +854,8 @@ function TeamMembersPanel({
844
854
  title = "Team members",
845
855
  description = "Manage who has access to this workspace."
846
856
  }) {
847
- const [inviteOpen, setInviteOpen] = React35.useState(false);
848
- const columns = React35.useMemo(() => [
857
+ const [inviteOpen, setInviteOpen] = React20.useState(false);
858
+ const columns = React20.useMemo(() => [
849
859
  {
850
860
  accessorKey: "name",
851
861
  header: "Name",
@@ -914,7 +924,7 @@ function BillingPanel({
914
924
  onUpdatePaymentMethod,
915
925
  className
916
926
  }) {
917
- const invoiceColumns = React35.useMemo(() => [
927
+ const invoiceColumns = React20.useMemo(() => [
918
928
  { accessorKey: "date", header: "Date", enableSorting: false },
919
929
  { accessorKey: "amount", header: "Amount", enableSorting: false },
920
930
  {
@@ -993,9 +1003,9 @@ function OnboardingWizard({
993
1003
  completeLabel = "Finish",
994
1004
  className
995
1005
  }) {
996
- const [internalStep, setInternalStep] = React35.useState(0);
997
- const [error, setError] = React35.useState(null);
998
- const [pending, setPending] = React35.useState(false);
1006
+ const [internalStep, setInternalStep] = React20.useState(0);
1007
+ const [error, setError] = React20.useState(null);
1008
+ const [pending, setPending] = React20.useState(false);
999
1009
  const index = stepProp ?? internalStep;
1000
1010
  const current = steps[index];
1001
1011
  const isLast = index === steps.length - 1;
@@ -1325,10 +1335,10 @@ function UpdateBanner({
1325
1335
  buttonLabel = "Refresh now",
1326
1336
  className
1327
1337
  }) {
1328
- const [show, setShow] = React35.useState(forceShow);
1329
- const [entered, setEntered] = React35.useState(false);
1330
- const [refreshing, setRefreshing] = React35.useState(false);
1331
- React35.useEffect(() => {
1338
+ const [show, setShow] = React20.useState(forceShow);
1339
+ const [entered, setEntered] = React20.useState(false);
1340
+ const [refreshing, setRefreshing] = React20.useState(false);
1341
+ React20.useEffect(() => {
1332
1342
  if (forceShow) {
1333
1343
  setShow(true);
1334
1344
  return;
@@ -1351,7 +1361,7 @@ function UpdateBanner({
1351
1361
  clearInterval(id);
1352
1362
  };
1353
1363
  }, [currentVersion, fetchVersion, forceShow, intervalMs]);
1354
- React35.useEffect(() => {
1364
+ React20.useEffect(() => {
1355
1365
  if (!show) {
1356
1366
  setEntered(false);
1357
1367
  return;
@@ -1424,9 +1434,9 @@ function FadeIn({
1424
1434
  style,
1425
1435
  ...props
1426
1436
  }) {
1427
- const ref = React35.useRef(null);
1428
- const [visible, setVisible] = React35.useState(false);
1429
- React35.useEffect(() => {
1437
+ const ref = React20.useRef(null);
1438
+ const [visible, setVisible] = React20.useState(false);
1439
+ React20.useEffect(() => {
1430
1440
  const el = ref.current;
1431
1441
  if (!el) return;
1432
1442
  const observer = new IntersectionObserver(
@@ -1621,16 +1631,16 @@ function Carousel({
1621
1631
  className
1622
1632
  }) {
1623
1633
  const mode = useUIVariant();
1624
- const trackRef = React35.useRef(null);
1625
- const [canPrev, setCanPrev] = React35.useState(false);
1626
- const [canNext, setCanNext] = React35.useState(true);
1627
- const updateScrollState = React35.useCallback(() => {
1634
+ const trackRef = React20.useRef(null);
1635
+ const [canPrev, setCanPrev] = React20.useState(false);
1636
+ const [canNext, setCanNext] = React20.useState(true);
1637
+ const updateScrollState = React20.useCallback(() => {
1628
1638
  const track = trackRef.current;
1629
1639
  if (!track) return;
1630
1640
  setCanPrev(track.scrollLeft > 8);
1631
1641
  setCanNext(track.scrollLeft < track.scrollWidth - track.clientWidth - 8);
1632
1642
  }, []);
1633
- React35.useEffect(() => {
1643
+ React20.useEffect(() => {
1634
1644
  const track = trackRef.current;
1635
1645
  if (!track) return;
1636
1646
  updateScrollState();
@@ -1687,7 +1697,7 @@ function Carousel({
1687
1697
  role: "region",
1688
1698
  "aria-label": ariaLabel,
1689
1699
  className: "flex snap-x snap-mandatory gap-6 overflow-x-auto pb-4 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
1690
- children: React35.Children.map(
1700
+ children: React20.Children.map(
1691
1701
  children,
1692
1702
  (child) => child == null ? null : /* @__PURE__ */ jsx("div", { "data-carousel-item": true, className: cn$1("shrink-0 snap-start", itemClassName), children: child })
1693
1703
  )
@@ -1712,9 +1722,9 @@ function StaggerChildren({
1712
1722
  className,
1713
1723
  ...props
1714
1724
  }) {
1715
- const ref = React35.useRef(null);
1716
- const [visible, setVisible] = React35.useState(false);
1717
- React35.useEffect(() => {
1725
+ const ref = React20.useRef(null);
1726
+ const [visible, setVisible] = React20.useState(false);
1727
+ React20.useEffect(() => {
1718
1728
  const el = ref.current;
1719
1729
  if (!el) return;
1720
1730
  const observer = new IntersectionObserver(
@@ -1732,7 +1742,7 @@ function StaggerChildren({
1732
1742
  return () => observer.disconnect();
1733
1743
  }, [once]);
1734
1744
  const [tx, ty] = translateMap2[direction];
1735
- return /* @__PURE__ */ jsx("div", { ref, className: cn$1(className), ...props, children: React35.Children.map(children, (child, i) => /* @__PURE__ */ jsx(
1745
+ return /* @__PURE__ */ jsx("div", { ref, className: cn$1(className), ...props, children: React20.Children.map(children, (child, i) => /* @__PURE__ */ jsx(
1736
1746
  "div",
1737
1747
  {
1738
1748
  className: "h-full",
@@ -1874,7 +1884,7 @@ function StepsSection({
1874
1884
  /* @__PURE__ */ jsx("div", { className: "mt-12", children: resolvedGroups.map((group, groupIndex) => {
1875
1885
  const startNumber = nextNumber;
1876
1886
  nextNumber += group.steps.length;
1877
- return /* @__PURE__ */ jsxs(React35.Fragment, { children: [
1887
+ return /* @__PURE__ */ jsxs(React20.Fragment, { children: [
1878
1888
  /* @__PURE__ */ jsx("div", { className: cn$1(groupIndex > 0 && "mt-10"), children: /* @__PURE__ */ jsx(TimelineGroup, { steps: group.steps, startNumber, fadeIn: groupIndex > 0 }) }),
1879
1889
  group.after && /* @__PURE__ */ jsx("div", { className: "mt-16", children: group.after })
1880
1890
  ] }, groupIndex);
@@ -2044,9 +2054,9 @@ function FeatureMarqueeSection({
2044
2054
  ] });
2045
2055
  }
2046
2056
  function useIntersectionObserver(options) {
2047
- const ref = React35.useRef(null);
2048
- const [isIntersecting, setIsIntersecting] = React35.useState(false);
2049
- React35.useEffect(() => {
2057
+ const ref = React20.useRef(null);
2058
+ const [isIntersecting, setIsIntersecting] = React20.useState(false);
2059
+ React20.useEffect(() => {
2050
2060
  const el = ref.current;
2051
2061
  if (!el) return;
2052
2062
  const observer = new IntersectionObserver(([entry]) => {
@@ -2068,8 +2078,8 @@ function ShowcaseCta({
2068
2078
  sectionClasses
2069
2079
  }) {
2070
2080
  const [ref, intersecting] = useIntersectionObserver({ threshold: 0.15 });
2071
- const [visible, setVisible] = React35.useState(false);
2072
- React35.useEffect(() => {
2081
+ const [visible, setVisible] = React20.useState(false);
2082
+ React20.useEffect(() => {
2073
2083
  if (intersecting) setVisible(true);
2074
2084
  }, [intersecting]);
2075
2085
  return /* @__PURE__ */ jsxs(
@@ -2153,6 +2163,122 @@ function CtaSection(props) {
2153
2163
  ] }) })
2154
2164
  ] }) });
2155
2165
  }
2166
+ var EFFECTS = {
2167
+ // Odometer. No opacity at all — the two values are solid and one physically
2168
+ // displaces the other, which is what makes it read as a mechanism rather
2169
+ // than a crossfade. Needs `clip`, or the departing value is legible above
2170
+ // the container the whole way out.
2171
+ roll: {
2172
+ clip: true,
2173
+ duration: 320,
2174
+ easing: "cubic-bezier(0.22, 1, 0.36, 1)",
2175
+ enter: { from: { transform: "translateY(100%)" }, to: { transform: "translateY(0)" } },
2176
+ exit: { from: { transform: "translateY(0)" }, to: { transform: "translateY(-100%)" } }
2177
+ },
2178
+ // The neutral one. No movement, so it never fights a layout that's also
2179
+ // reflowing around it.
2180
+ fade: {
2181
+ clip: false,
2182
+ duration: 220,
2183
+ easing: "ease",
2184
+ enter: { from: { opacity: 0 }, to: { opacity: 1 } },
2185
+ exit: { from: { opacity: 1 }, to: { opacity: 0 } }
2186
+ },
2187
+ // Horizontal, and short: 0.75rem of travel carried by opacity, so it needs
2188
+ // no clipping and won't crop a ring or drop shadow on whatever it wraps.
2189
+ slide: {
2190
+ clip: false,
2191
+ duration: 280,
2192
+ easing: "cubic-bezier(0.4, 0, 0.2, 1)",
2193
+ enter: {
2194
+ from: { opacity: 0, transform: "translateX(0.75rem)" },
2195
+ to: { opacity: 1, transform: "translateX(0)" }
2196
+ },
2197
+ exit: {
2198
+ from: { opacity: 1, transform: "translateX(0)" },
2199
+ to: { opacity: 0, transform: "translateX(-0.75rem)" }
2200
+ }
2201
+ }
2202
+ };
2203
+ var MODE_EFFECT = {
2204
+ default: "fade",
2205
+ playful: "roll",
2206
+ smooth: "slide"
2207
+ };
2208
+ function AnimatedSwap({
2209
+ swapKey,
2210
+ effect,
2211
+ duration,
2212
+ children,
2213
+ className,
2214
+ style,
2215
+ ...props
2216
+ }) {
2217
+ const mode = useUIMode();
2218
+ const resolved = effect ?? MODE_EFFECT[mode];
2219
+ const spec = typeof resolved !== "string" ? resolved : resolved === "none" ? null : EFFECTS[resolved];
2220
+ const ms = duration ?? spec?.duration ?? 0;
2221
+ const reduced = usePrefersReducedMotion();
2222
+ const animated = spec !== null && !reduced;
2223
+ const previous = React20.useRef(children);
2224
+ const seenKey = React20.useRef(swapKey);
2225
+ const [swap, setSwap] = React20.useState(null);
2226
+ if (seenKey.current !== swapKey) {
2227
+ const out = previous.current;
2228
+ seenKey.current = swapKey;
2229
+ if (animated) setSwap({ key: swapKey, out, running: false });
2230
+ }
2231
+ React20.useEffect(() => {
2232
+ previous.current = children;
2233
+ });
2234
+ React20.useEffect(() => {
2235
+ if (!swap || swap.running) return;
2236
+ const raf = requestAnimationFrame(() => {
2237
+ setSwap((s) => s && s.key === swap.key ? { ...s, running: true } : s);
2238
+ });
2239
+ return () => cancelAnimationFrame(raf);
2240
+ }, [swap]);
2241
+ React20.useEffect(() => {
2242
+ if (!swap?.running) return;
2243
+ const done = setTimeout(() => {
2244
+ setSwap((s) => s && s.key === swap.key ? null : s);
2245
+ }, ms);
2246
+ return () => clearTimeout(done);
2247
+ }, [swap, ms]);
2248
+ const phase = (layer) => {
2249
+ if (!swap || !spec) return void 0;
2250
+ return {
2251
+ ...spec[layer][swap.running ? "to" : "from"],
2252
+ transition: `transform ${ms}ms ${spec.easing}, opacity ${ms}ms ${spec.easing}`
2253
+ };
2254
+ };
2255
+ return /* @__PURE__ */ jsxs(
2256
+ "span",
2257
+ {
2258
+ className: cn$1("relative inline-block", swap && spec?.clip && "overflow-hidden", className),
2259
+ style,
2260
+ ...props,
2261
+ children: [
2262
+ /* @__PURE__ */ jsx("span", { className: "block", style: phase("enter"), children }),
2263
+ swap && // Pinned rather than inset-0: stretching the outgoing copy to the
2264
+ // incoming one's box would resize it mid-exit.
2265
+ /* @__PURE__ */ jsx("span", { className: "absolute left-0 top-0 block", "aria-hidden": "true", style: phase("exit"), children: swap.out })
2266
+ ]
2267
+ }
2268
+ );
2269
+ }
2270
+ function usePrefersReducedMotion() {
2271
+ const [reduced, setReduced] = React20.useState(false);
2272
+ React20.useEffect(() => {
2273
+ const query = window.matchMedia?.("(prefers-reduced-motion: reduce)");
2274
+ if (!query) return;
2275
+ setReduced(query.matches);
2276
+ const onChange = (e) => setReduced(e.matches);
2277
+ query.addEventListener("change", onChange);
2278
+ return () => query.removeEventListener("change", onChange);
2279
+ }, []);
2280
+ return reduced;
2281
+ }
2156
2282
  function PricingCard({
2157
2283
  name,
2158
2284
  price,
@@ -2186,7 +2312,7 @@ function PricingCard({
2186
2312
  /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
2187
2313
  /* @__PURE__ */ jsx("div", { className: "text-sm font-medium text-muted-foreground", children: name }),
2188
2314
  /* @__PURE__ */ jsxs("div", { className: "flex items-end gap-1", children: [
2189
- /* @__PURE__ */ jsx("span", { className: "text-4xl font-bold tracking-tight", children: price }),
2315
+ /* @__PURE__ */ jsx(AnimatedSwap, { swapKey: price, className: "text-4xl font-bold tracking-tight", children: price }),
2190
2316
  /* @__PURE__ */ jsx("span", { className: "mb-1 text-sm text-muted-foreground", children: period })
2191
2317
  ] }),
2192
2318
  /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: description })
@@ -2246,8 +2372,8 @@ function CountdownTimer({
2246
2372
  className,
2247
2373
  compact = false
2248
2374
  }) {
2249
- const [timeLeft, setTimeLeft] = React35.useState(() => getTimeLeft(deadline));
2250
- React35.useEffect(() => {
2375
+ const [timeLeft, setTimeLeft] = React20.useState(() => getTimeLeft(deadline));
2376
+ React20.useEffect(() => {
2251
2377
  setTimeLeft(getTimeLeft(deadline));
2252
2378
  const id = setInterval(() => setTimeLeft(getTimeLeft(deadline)), 1e3);
2253
2379
  return () => clearInterval(id);
@@ -2273,7 +2399,7 @@ function CountdownTimer({
2273
2399
  ];
2274
2400
  return /* @__PURE__ */ jsxs("div", { className: cn$1("flex items-center justify-center gap-2 text-sm", className), children: [
2275
2401
  /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: label }),
2276
- /* @__PURE__ */ jsx("span", { className: "flex items-center gap-1 font-mono font-semibold tabular-nums", children: units.map(({ value, unit }, i) => /* @__PURE__ */ jsxs(React35.Fragment, { children: [
2402
+ /* @__PURE__ */ jsx("span", { className: "flex items-center gap-1 font-mono font-semibold tabular-nums", children: units.map(({ value, unit }, i) => /* @__PURE__ */ jsxs(React20.Fragment, { children: [
2277
2403
  /* @__PURE__ */ jsxs("span", { children: [
2278
2404
  String(value).padStart(2, "0"),
2279
2405
  /* @__PURE__ */ jsx("span", { className: "font-normal text-muted-foreground", children: unit })
@@ -2328,13 +2454,13 @@ function PricingSection({
2328
2454
  onSelectPlan,
2329
2455
  pendingPlanName
2330
2456
  }) {
2331
- const [annual, setAnnual] = React35.useState(false);
2457
+ const [annual, setAnnual] = React20.useState(false);
2332
2458
  const isOneTime = mode === "one-time";
2333
2459
  const useCadences = !!cadences?.length;
2334
2460
  const initialCadence = (defaultCadence && cadences?.some((c) => c.key === defaultCadence) ? defaultCadence : null) ?? cadences?.[0]?.key ?? "";
2335
- const [activeCadence, setActiveCadence] = React35.useState(initialCadence);
2461
+ const [activeCadence, setActiveCadence] = React20.useState(initialCadence);
2336
2462
  const cadence = cadences?.find((c) => c.key === activeCadence);
2337
- const saveBadges = React35.useMemo(
2463
+ const saveBadges = React20.useMemo(
2338
2464
  () => useCadences ? computeSaveBadges(plans, cadences, initialCadence) : {},
2339
2465
  [useCadences, plans, cadences, initialCadence]
2340
2466
  );
@@ -2628,10 +2754,10 @@ function CountUp({
2628
2754
  className,
2629
2755
  ...props
2630
2756
  }) {
2631
- const ref = React35.useRef(null);
2632
- const [value, setValue] = React35.useState(from);
2633
- const hasStarted = React35.useRef(false);
2634
- React35.useEffect(() => {
2757
+ const ref = React20.useRef(null);
2758
+ const [value, setValue] = React20.useState(from);
2759
+ const hasStarted = React20.useRef(false);
2760
+ React20.useEffect(() => {
2635
2761
  const el = ref.current;
2636
2762
  if (!el) return;
2637
2763
  const observer = new IntersectionObserver(
@@ -2724,8 +2850,8 @@ function NewsletterSection({
2724
2850
  successDescription = defaults.successDescription,
2725
2851
  onSubscribe
2726
2852
  } = {}) {
2727
- const [email, setEmail] = React35.useState("");
2728
- const [submitted, setSubmitted] = React35.useState(false);
2853
+ const [email, setEmail] = React20.useState("");
2854
+ const [submitted, setSubmitted] = React20.useState(false);
2729
2855
  const mode = useUIVariant();
2730
2856
  const sectionClasses = cn$1(
2731
2857
  "overflow-hidden bg-card",
@@ -2816,7 +2942,7 @@ function ContactSection({
2816
2942
  sendAnotherLabel = defaults2.sendAnotherLabel,
2817
2943
  onSubmit
2818
2944
  } = {}) {
2819
- const [submitted, setSubmitted] = React35.useState(false);
2945
+ const [submitted, setSubmitted] = React20.useState(false);
2820
2946
  const mode = useUIVariant();
2821
2947
  const sectionClasses = cn$1(
2822
2948
  "overflow-hidden bg-card",
@@ -3114,10 +3240,10 @@ function Navbar({
3114
3240
  controls,
3115
3241
  renderLink = defaultRenderLink7
3116
3242
  }) {
3117
- const [open, setOpen] = React35.useState(false);
3243
+ const [open, setOpen] = React20.useState(false);
3118
3244
  const brandHref = brand.href ?? "/";
3119
3245
  const hasRightContent = controls?.length || cta?.primary || cta?.secondary;
3120
- const closeMobileMenu = React35.useCallback(() => setOpen(false), []);
3246
+ const closeMobileMenu = React20.useCallback(() => setOpen(false), []);
3121
3247
  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: [
3122
3248
  renderLink({
3123
3249
  href: brandHref,
@@ -3132,7 +3258,7 @@ function Navbar({
3132
3258
  children: link.label
3133
3259
  }) }, link.label)) }),
3134
3260
  hasRightContent && /* @__PURE__ */ jsxs("div", { className: "hidden items-center justify-end gap-2 md:flex", children: [
3135
- controls?.map((control, i) => /* @__PURE__ */ jsx(React35.Fragment, { children: control }, i)),
3261
+ controls?.map((control, i) => /* @__PURE__ */ jsx(React20.Fragment, { children: control }, i)),
3136
3262
  (cta?.secondary || cta?.primary) && controls?.length ? /* @__PURE__ */ jsx("div", { className: "mx-1 h-4 w-px bg-border" }) : null,
3137
3263
  cta?.secondary && renderLink({
3138
3264
  href: cta.secondary.href,
@@ -3156,7 +3282,7 @@ function Navbar({
3156
3282
  /* @__PURE__ */ jsx("span", { children: brand.name })
3157
3283
  ] })
3158
3284
  }) }) }),
3159
- controls?.length ? /* @__PURE__ */ jsx("div", { className: "mb-4 flex w-full items-center justify-between gap-1", children: controls.map((control, i) => /* @__PURE__ */ jsx(React35.Fragment, { children: control }, i)) }) : null,
3285
+ controls?.length ? /* @__PURE__ */ jsx("div", { className: "mb-4 flex w-full items-center justify-between gap-1", children: controls.map((control, i) => /* @__PURE__ */ jsx(React20.Fragment, { children: control }, i)) }) : null,
3160
3286
  /* @__PURE__ */ jsx(Separator, {}),
3161
3287
  /* @__PURE__ */ jsx("nav", { className: "mt-4 flex flex-col gap-1", children: navLinks.map((link) => /* @__PURE__ */ jsx("span", { onClickCapture: closeMobileMenu, children: renderLink({
3162
3288
  href: link.href,
@@ -3305,7 +3431,7 @@ function LogoStrip({
3305
3431
  ] });
3306
3432
  }
3307
3433
  function GridUnderlay({ variant, size = 24, className, ...props }) {
3308
- const id = React35.useId();
3434
+ const id = React20.useId();
3309
3435
  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: [
3310
3436
  /* @__PURE__ */ jsx("line", { x1: size / 2, y1: 0, x2: size / 2, y2: size, stroke: "currentColor", strokeWidth: 0.5 }),
3311
3437
  /* @__PURE__ */ jsx("line", { x1: 0, y1: size / 2, x2: size, y2: size / 2, stroke: "currentColor", strokeWidth: 0.5 })
@@ -3333,9 +3459,9 @@ function GlowUnderlay({
3333
3459
  style,
3334
3460
  ...props
3335
3461
  }) {
3336
- const [pos, setPos] = React35.useState({ x: "50%", y: "50%" });
3337
- const containerRef = React35.useRef(null);
3338
- React35.useEffect(() => {
3462
+ const [pos, setPos] = React20.useState({ x: "50%", y: "50%" });
3463
+ const containerRef = React20.useRef(null);
3464
+ React20.useEffect(() => {
3339
3465
  if (!followCursor) return;
3340
3466
  const handleMouseMove = (e) => {
3341
3467
  const el = containerRef.current;
@@ -3474,8 +3600,8 @@ function PageTransition({
3474
3600
  style,
3475
3601
  ...props
3476
3602
  }) {
3477
- const [mounted, setMounted] = React35.useState(false);
3478
- React35.useEffect(() => {
3603
+ const [mounted, setMounted] = React20.useState(false);
3604
+ React20.useEffect(() => {
3479
3605
  const id = requestAnimationFrame(() => setMounted(true));
3480
3606
  return () => cancelAnimationFrame(id);
3481
3607
  }, []);
@@ -3550,7 +3676,7 @@ function Sortable({
3550
3676
  if (oldIndex === -1 || newIndex === -1) return;
3551
3677
  onReorder(arrayMove(items, oldIndex, newIndex));
3552
3678
  };
3553
- const childArray = React35.Children.toArray(children);
3679
+ const childArray = React20.Children.toArray(children);
3554
3680
  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(
3555
3681
  (child, i) => items[i] === void 0 ? null : /* @__PURE__ */ jsx(SortableItem, { id: items[i], disabled, className: itemClassName, children: child }, items[i])
3556
3682
  ) }) }) });
@@ -3562,8 +3688,8 @@ function Spotlight({
3562
3688
  triggerClassName,
3563
3689
  shortcut = "\u2318K"
3564
3690
  }) {
3565
- const [open, setOpen] = React35.useState(false);
3566
- React35.useEffect(() => {
3691
+ const [open, setOpen] = React20.useState(false);
3692
+ React20.useEffect(() => {
3567
3693
  const down = (e) => {
3568
3694
  if (e.key === "k" && (e.metaKey || e.ctrlKey)) {
3569
3695
  e.preventDefault();
@@ -3593,7 +3719,7 @@ function Spotlight({
3593
3719
  /* @__PURE__ */ jsx(CommandInput, { placeholder }),
3594
3720
  /* @__PURE__ */ jsxs(CommandList, { children: [
3595
3721
  /* @__PURE__ */ jsx(CommandEmpty, { children: "No results found." }),
3596
- groups.map((group, i) => /* @__PURE__ */ jsxs(React35.Fragment, { children: [
3722
+ groups.map((group, i) => /* @__PURE__ */ jsxs(React20.Fragment, { children: [
3597
3723
  i > 0 && /* @__PURE__ */ jsx(CommandSeparator, {}),
3598
3724
  /* @__PURE__ */ jsx(CommandGroup, { heading: group.heading, children: group.items.map((item) => /* @__PURE__ */ jsxs(
3599
3725
  CommandItem,
@@ -3618,8 +3744,8 @@ function Spotlight({
3618
3744
  var BASE = 40;
3619
3745
  var MAGNIFY_RADIUS = 80;
3620
3746
  function Dock({ items, iconSize = BASE, magnification = 1.7, className, ...props }) {
3621
- const [mouseX, setMouseX] = React35.useState(null);
3622
- const containerRef = React35.useRef(null);
3747
+ const [mouseX, setMouseX] = React20.useState(null);
3748
+ const containerRef = React20.useRef(null);
3623
3749
  function getScale(index) {
3624
3750
  if (mouseX === null || !containerRef.current) return 1;
3625
3751
  const container = containerRef.current;
@@ -3718,7 +3844,7 @@ function ConfirmDialog({ isOpen, options, handleConfirm, handleCancel, destructi
3718
3844
  ] }) });
3719
3845
  }
3720
3846
  function RegisterHotkeys({ hotkeys }) {
3721
- React35.useEffect(() => {
3847
+ React20.useEffect(() => {
3722
3848
  const handleKeyDown = (event) => {
3723
3849
  for (const hotkey of hotkeys) {
3724
3850
  const matches = event.key.toLowerCase() === hotkey.key.toLowerCase() && !!event.ctrlKey === !!hotkey.ctrl && !!event.metaKey === !!hotkey.meta && !!event.shiftKey === !!hotkey.shift && !!event.altKey === !!hotkey.alt;
@@ -3735,10 +3861,10 @@ function RegisterHotkeys({ hotkeys }) {
3735
3861
  return null;
3736
3862
  }
3737
3863
  function useControlledOpen(defaultOpen = false) {
3738
- const [isOpen, setIsOpen] = React35.useState(defaultOpen);
3739
- const open = React35.useCallback(() => setIsOpen(true), []);
3740
- const close = React35.useCallback(() => setIsOpen(false), []);
3741
- const toggle = React35.useCallback(() => setIsOpen((prev) => !prev), []);
3864
+ const [isOpen, setIsOpen] = React20.useState(defaultOpen);
3865
+ const open = React20.useCallback(() => setIsOpen(true), []);
3866
+ const close = React20.useCallback(() => setIsOpen(false), []);
3867
+ const toggle = React20.useCallback(() => setIsOpen((prev) => !prev), []);
3742
3868
  return { isOpen, open, close, toggle, setIsOpen };
3743
3869
  }
3744
3870
  function CommandMenu({
@@ -3751,7 +3877,7 @@ function CommandMenu({
3751
3877
  }) {
3752
3878
  const internal = useControlledOpen(false);
3753
3879
  const isOpen = openProp ?? internal.isOpen;
3754
- const setOpen = React35.useCallback(
3880
+ const setOpen = React20.useCallback(
3755
3881
  (next) => {
3756
3882
  if (openProp === void 0) internal.setIsOpen(next);
3757
3883
  onOpenChange?.(next);
@@ -3776,7 +3902,7 @@ function CommandMenu({
3776
3902
  /* @__PURE__ */ jsx(CommandInput, { placeholder }),
3777
3903
  /* @__PURE__ */ jsxs(CommandList, { children: [
3778
3904
  /* @__PURE__ */ jsx(CommandEmpty, { children: emptyMessage }),
3779
- groups.map((group, i) => /* @__PURE__ */ jsxs(React35.Fragment, { children: [
3905
+ groups.map((group, i) => /* @__PURE__ */ jsxs(React20.Fragment, { children: [
3780
3906
  i > 0 && /* @__PURE__ */ jsx(CommandSeparator, {}),
3781
3907
  /* @__PURE__ */ jsx(CommandGroup, { heading: group.heading, children: group.items.map((item) => /* @__PURE__ */ jsxs(
3782
3908
  CommandItem,
@@ -3831,7 +3957,7 @@ function DataView({
3831
3957
  }
3832
3958
  );
3833
3959
  }
3834
- return /* @__PURE__ */ jsx(AppGrid, { columns: gridColumns, gap, className: cn$1(className), children: items.map((item) => /* @__PURE__ */ jsx(React35.Fragment, { children: renderCard(item) }, getRowId(item))) });
3960
+ return /* @__PURE__ */ jsx(AppGrid, { columns: gridColumns, gap, className: cn$1(className), children: items.map((item) => /* @__PURE__ */ jsx(React20.Fragment, { children: renderCard(item) }, getRowId(item))) });
3835
3961
  }
3836
3962
  var TOKEN_COLORS = ["var(--chart-1)", "var(--chart-2)", "var(--chart-3)", "var(--chart-4)", "var(--chart-5)"];
3837
3963
  var seriesColor = (s, i) => s.color ?? TOKEN_COLORS[i % TOKEN_COLORS.length];
@@ -4005,20 +4131,20 @@ function FileUpload({
4005
4131
  hint,
4006
4132
  className
4007
4133
  }) {
4008
- const [internalFiles, setInternalFiles] = React35.useState(defaultFiles ?? []);
4009
- const [isDragging, setIsDragging] = React35.useState(false);
4010
- const [validationError, setValidationError] = React35.useState(null);
4011
- const inputRef = React35.useRef(null);
4012
- const dragDepth = React35.useRef(0);
4134
+ const [internalFiles, setInternalFiles] = React20.useState(defaultFiles ?? []);
4135
+ const [isDragging, setIsDragging] = React20.useState(false);
4136
+ const [validationError, setValidationError] = React20.useState(null);
4137
+ const inputRef = React20.useRef(null);
4138
+ const dragDepth = React20.useRef(0);
4013
4139
  const files = filesProp ?? internalFiles;
4014
- const setFiles = React35.useCallback(
4140
+ const setFiles = React20.useCallback(
4015
4141
  (next) => {
4016
4142
  if (!filesProp) setInternalFiles(next);
4017
4143
  onFilesChange?.(next);
4018
4144
  },
4019
4145
  [filesProp, onFilesChange]
4020
4146
  );
4021
- const acceptList = React35.useMemo(
4147
+ const acceptList = React20.useMemo(
4022
4148
  () => accept?.split(",").map((a) => a.trim().toLowerCase()).filter(Boolean) ?? [],
4023
4149
  [accept]
4024
4150
  );
@@ -4742,7 +4868,7 @@ function PageHeader({
4742
4868
  return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-1 pb-6", className), children: [
4743
4869
  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) => {
4744
4870
  const isLast = i === breadcrumbs.length - 1;
4745
- return /* @__PURE__ */ jsxs(React35.Fragment, { children: [
4871
+ return /* @__PURE__ */ jsxs(React20.Fragment, { children: [
4746
4872
  i > 0 && /* @__PURE__ */ jsx(ChevronRight, { className: "size-3.5 shrink-0" }),
4747
4873
  isLast || !crumb.href ? /* @__PURE__ */ jsx("span", { className: cn(isLast && "text-foreground font-medium"), children: crumb.label }) : renderLink({
4748
4874
  href: crumb.href,
@@ -4778,7 +4904,7 @@ function PageHeader({
4778
4904
  ] });
4779
4905
  }
4780
4906
  function Suspensed({ children, fallback }) {
4781
- return /* @__PURE__ */ jsx(React35.Suspense, { fallback: fallback ?? /* @__PURE__ */ jsx(Spinner, {}), children });
4907
+ return /* @__PURE__ */ jsx(React20.Suspense, { fallback: fallback ?? /* @__PURE__ */ jsx(Spinner, {}), children });
4782
4908
  }
4783
4909
  function getInitialTheme() {
4784
4910
  if (typeof document === "undefined") return "dark";
@@ -4786,7 +4912,7 @@ function getInitialTheme() {
4786
4912
  return stored ?? (document.documentElement.classList.contains("dark") ? "dark" : "light");
4787
4913
  }
4788
4914
  function ThemeSwitchMinimal() {
4789
- const [theme, setThemeState] = React35.useState(getInitialTheme);
4915
+ const [theme, setThemeState] = React20.useState(getInitialTheme);
4790
4916
  const toggle = () => {
4791
4917
  const next = theme === "dark" ? "light" : "dark";
4792
4918
  setThemeState(next);
@@ -4912,9 +5038,9 @@ function getInitialColorName() {
4912
5038
  return localStorage.getItem(STORAGE_KEY) ?? "emerald";
4913
5039
  }
4914
5040
  function BrandColorSwitchMinimal() {
4915
- const [active, setActive] = React35.useState(getInitialColorName);
4916
- const [open, setOpen] = React35.useState(false);
4917
- React35.useEffect(() => {
5041
+ const [active, setActive] = React20.useState(getInitialColorName);
5042
+ const [open, setOpen] = React20.useState(false);
5043
+ React20.useEffect(() => {
4918
5044
  const saved = localStorage.getItem(STORAGE_KEY) ?? "emerald";
4919
5045
  const color = BRAND_COLORS.find((c) => c.name === saved);
4920
5046
  if (color) applyColor(color);
@@ -4975,7 +5101,7 @@ function BrandColorSwitchMinimal() {
4975
5101
  ] });
4976
5102
  }
4977
5103
  function ThemeColorUpdater({ colorTheme }) {
4978
- React35.useEffect(() => {
5104
+ React20.useEffect(() => {
4979
5105
  if (colorTheme) {
4980
5106
  document.documentElement.setAttribute("data-theme", colorTheme);
4981
5107
  } else {
@@ -4985,7 +5111,7 @@ function ThemeColorUpdater({ colorTheme }) {
4985
5111
  return null;
4986
5112
  }
4987
5113
  function VersionBanner({ version, message, className, onDismiss }) {
4988
- const [dismissed, setDismissed] = React35.useState(false);
5114
+ const [dismissed, setDismissed] = React20.useState(false);
4989
5115
  if (dismissed) return null;
4990
5116
  return /* @__PURE__ */ jsxs("div", { className: cn("flex items-center justify-between gap-4 bg-primary/10 px-4 py-2 text-sm", className), children: [
4991
5117
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
@@ -5242,29 +5368,29 @@ function useMounted() {
5242
5368
  return mounted;
5243
5369
  }
5244
5370
  function useConfirm() {
5245
- const [isOpen, setIsOpen] = React35.useState(false);
5246
- const [options, setOptions] = React35.useState({});
5247
- const resolveRef = React35.useRef(null);
5248
- const confirm = React35.useCallback((opts = {}) => {
5371
+ const [isOpen, setIsOpen] = React20.useState(false);
5372
+ const [options, setOptions] = React20.useState({});
5373
+ const resolveRef = React20.useRef(null);
5374
+ const confirm = React20.useCallback((opts = {}) => {
5249
5375
  setOptions(opts);
5250
5376
  setIsOpen(true);
5251
5377
  return new Promise((resolve) => {
5252
5378
  resolveRef.current = resolve;
5253
5379
  });
5254
5380
  }, []);
5255
- const handleConfirm = React35.useCallback(() => {
5381
+ const handleConfirm = React20.useCallback(() => {
5256
5382
  resolveRef.current?.(true);
5257
5383
  setIsOpen(false);
5258
5384
  }, []);
5259
- const handleCancel = React35.useCallback(() => {
5385
+ const handleCancel = React20.useCallback(() => {
5260
5386
  resolveRef.current?.(false);
5261
5387
  setIsOpen(false);
5262
5388
  }, []);
5263
5389
  return { confirm, isOpen, options, handleConfirm, handleCancel };
5264
5390
  }
5265
5391
  function useScrolledPast(threshold) {
5266
- const [scrolledPast, setScrolledPast] = React35.useState(false);
5267
- React35.useEffect(() => {
5392
+ const [scrolledPast, setScrolledPast] = React20.useState(false);
5393
+ React20.useEffect(() => {
5268
5394
  const handleScroll = () => {
5269
5395
  setScrolledPast(window.scrollY > threshold);
5270
5396
  };
@@ -5275,28 +5401,28 @@ function useScrolledPast(threshold) {
5275
5401
  return scrolledPast;
5276
5402
  }
5277
5403
  function useCopyToClipboard() {
5278
- const [copied, setCopied] = React35.useState(false);
5279
- const timeoutRef = React35.useRef(void 0);
5280
- const copy = React35.useCallback((text) => {
5404
+ const [copied, setCopied] = React20.useState(false);
5405
+ const timeoutRef = React20.useRef(void 0);
5406
+ const copy = React20.useCallback((text) => {
5281
5407
  navigator.clipboard.writeText(text).then(() => {
5282
5408
  setCopied(true);
5283
5409
  clearTimeout(timeoutRef.current);
5284
5410
  timeoutRef.current = setTimeout(() => setCopied(false), 2e3);
5285
5411
  });
5286
5412
  }, []);
5287
- React35.useEffect(() => () => clearTimeout(timeoutRef.current), []);
5413
+ React20.useEffect(() => () => clearTimeout(timeoutRef.current), []);
5288
5414
  return [copied, copy];
5289
5415
  }
5290
5416
  function useDebounce(value, delay) {
5291
- const [debounced, setDebounced] = React35.useState(value);
5292
- React35.useEffect(() => {
5417
+ const [debounced, setDebounced] = React20.useState(value);
5418
+ React20.useEffect(() => {
5293
5419
  const timer = setTimeout(() => setDebounced(value), delay);
5294
5420
  return () => clearTimeout(timer);
5295
5421
  }, [value, delay]);
5296
5422
  return debounced;
5297
5423
  }
5298
5424
  function useLocalStorage(key, initialValue) {
5299
- const [storedValue, setStoredValue] = React35.useState(() => {
5425
+ const [storedValue, setStoredValue] = React20.useState(() => {
5300
5426
  if (typeof window === "undefined") return initialValue;
5301
5427
  try {
5302
5428
  const item = window.localStorage.getItem(key);
@@ -5305,7 +5431,7 @@ function useLocalStorage(key, initialValue) {
5305
5431
  return initialValue;
5306
5432
  }
5307
5433
  });
5308
- const setValue = React35.useCallback(
5434
+ const setValue = React20.useCallback(
5309
5435
  (value) => {
5310
5436
  try {
5311
5437
  setStoredValue(value);
@@ -5327,11 +5453,11 @@ function useViewMode(key = "view-mode", fallback = "cards") {
5327
5453
  return { view: mounted ? stored : fallback, setView: setStored, ready: mounted };
5328
5454
  }
5329
5455
  function useMediaQuery(query) {
5330
- const [matches, setMatches] = React35.useState(() => {
5456
+ const [matches, setMatches] = React20.useState(() => {
5331
5457
  if (typeof window === "undefined") return false;
5332
5458
  return window.matchMedia(query).matches;
5333
5459
  });
5334
- React35.useEffect(() => {
5460
+ React20.useEffect(() => {
5335
5461
  if (typeof window === "undefined") return;
5336
5462
  const mql = window.matchMedia(query);
5337
5463
  setMatches(mql.matches);
@@ -5342,18 +5468,18 @@ function useMediaQuery(query) {
5342
5468
  return matches;
5343
5469
  }
5344
5470
  function usePagination(total, pageSize) {
5345
- const [page, setPage] = React35.useState(1);
5471
+ const [page, setPage] = React20.useState(1);
5346
5472
  const totalPages = Math.max(1, Math.ceil(total / pageSize));
5347
5473
  const offset = (page - 1) * pageSize;
5348
- const goTo = React35.useCallback(
5474
+ const goTo = React20.useCallback(
5349
5475
  (p) => setPage(Math.min(Math.max(1, p), totalPages)),
5350
5476
  [totalPages]
5351
5477
  );
5352
- const next = React35.useCallback(() => goTo(page + 1), [page, goTo]);
5353
- const prev = React35.useCallback(() => goTo(page - 1), [page, goTo]);
5478
+ const next = React20.useCallback(() => goTo(page + 1), [page, goTo]);
5479
+ const prev = React20.useCallback(() => goTo(page - 1), [page, goTo]);
5354
5480
  return { page, pageSize, totalPages, offset, hasPrev: page > 1, hasNext: page < totalPages, goTo, next, prev };
5355
5481
  }
5356
5482
 
5357
- 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, DataView, DevBanner, Dock, EmptyState, ErrorPage, FadeIn, FaqSection, FeatureCard, FeatureMarqueeSection, FeaturesSection, FileUpload, FlowBracket, FlowConnector, Footer, FullPageSpinner, GlassCard, Grid, GridItem, GroupedFeaturesSection, HeroSection, ImageCard, Input, LogoStrip, MediaCard, 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, ViewToggle, marketingSectionSpacing, notify, useConfirm, useControlledOpen, useCopyToClipboard, useDebounce, useIntersectionObserver, useLocalStorage, useMediaQuery, useMounted, useOlwibaUI, usePagination, useScrolledPast, useUIMode, useViewMode };
5483
+ export { ActivityFeed, AnimatedPill, AnimatedSwap, 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, DataView, DevBanner, Dock, EmptyState, ErrorPage, FadeIn, FaqSection, FeatureCard, FeatureMarqueeSection, FeaturesSection, FileUpload, FlowBracket, FlowConnector, Footer, FullPageSpinner, GlassCard, Grid, GridItem, GroupedFeaturesSection, HeroSection, ImageCard, Input, LogoStrip, MediaCard, 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, ViewToggle, marketingSectionSpacing, notify, useConfirm, useControlledOpen, useCopyToClipboard, useDebounce, useIntersectionObserver, useLocalStorage, useMediaQuery, useMounted, useOlwibaUI, usePagination, useScrolledPast, useUIMode, useViewMode };
5358
5484
  //# sourceMappingURL=index.js.map
5359
5485
  //# sourceMappingURL=index.js.map