@olwiba/ui 0.2.10 → 0.2.11

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: [
@@ -534,7 +538,7 @@ function DefaultForm({
534
538
  const isForgotPassword = mode === "forgot-password";
535
539
  const isResetPassword = mode === "reset-password";
536
540
  const isVerify = mode === "verify";
537
- const [code, setCode] = React35.useState("");
541
+ const [code, setCode] = React20.useState("");
538
542
  const hasPrefill = !!(defaultEmail || defaultPassword);
539
543
  const prefillStyle = (active) => active ? { animation: "auth-prefill 1.6s ease-out 0.35s 1 both" } : void 0;
540
544
  const copy = authCopy[mode];
@@ -694,10 +698,10 @@ function DataTable({
694
698
  emptyMessage = "No results.",
695
699
  className
696
700
  }) {
697
- const [sorting, setSorting] = React35.useState([]);
698
- const [rowSelection, setRowSelection] = React35.useState({});
699
- const [globalFilter, setGlobalFilter] = React35.useState("");
700
- const allColumns = React35.useMemo(
701
+ const [sorting, setSorting] = React20.useState([]);
702
+ const [rowSelection, setRowSelection] = React20.useState({});
703
+ const [globalFilter, setGlobalFilter] = React20.useState("");
704
+ const allColumns = React20.useMemo(
701
705
  () => selectable ? [selectColumn, ...columns] : columns,
702
706
  [selectable, columns]
703
707
  );
@@ -719,7 +723,7 @@ function DataTable({
719
723
  initialState: pageSize > 0 ? { pagination: { pageSize } } : void 0,
720
724
  enableRowSelection: selectable
721
725
  });
722
- React35.useEffect(() => {
726
+ React20.useEffect(() => {
723
727
  if (!onSelectionChange) return;
724
728
  onSelectionChange(table.getSelectedRowModel().rows.map((r) => r.original));
725
729
  }, [rowSelection]);
@@ -799,8 +803,8 @@ function DataTable({
799
803
  ] });
800
804
  }
801
805
  function InviteDialog({ roles, onInvite, onClose }) {
802
- const [email, setEmail] = React35.useState("");
803
- const [role, setRole] = React35.useState(roles[roles.length - 1] ?? roles[0]);
806
+ const [email, setEmail] = React20.useState("");
807
+ const [role, setRole] = React20.useState(roles[roles.length - 1] ?? roles[0]);
804
808
  return /* @__PURE__ */ jsx(DialogContent, { children: /* @__PURE__ */ jsxs(
805
809
  "form",
806
810
  {
@@ -844,8 +848,8 @@ function TeamMembersPanel({
844
848
  title = "Team members",
845
849
  description = "Manage who has access to this workspace."
846
850
  }) {
847
- const [inviteOpen, setInviteOpen] = React35.useState(false);
848
- const columns = React35.useMemo(() => [
851
+ const [inviteOpen, setInviteOpen] = React20.useState(false);
852
+ const columns = React20.useMemo(() => [
849
853
  {
850
854
  accessorKey: "name",
851
855
  header: "Name",
@@ -914,7 +918,7 @@ function BillingPanel({
914
918
  onUpdatePaymentMethod,
915
919
  className
916
920
  }) {
917
- const invoiceColumns = React35.useMemo(() => [
921
+ const invoiceColumns = React20.useMemo(() => [
918
922
  { accessorKey: "date", header: "Date", enableSorting: false },
919
923
  { accessorKey: "amount", header: "Amount", enableSorting: false },
920
924
  {
@@ -993,9 +997,9 @@ function OnboardingWizard({
993
997
  completeLabel = "Finish",
994
998
  className
995
999
  }) {
996
- const [internalStep, setInternalStep] = React35.useState(0);
997
- const [error, setError] = React35.useState(null);
998
- const [pending, setPending] = React35.useState(false);
1000
+ const [internalStep, setInternalStep] = React20.useState(0);
1001
+ const [error, setError] = React20.useState(null);
1002
+ const [pending, setPending] = React20.useState(false);
999
1003
  const index = stepProp ?? internalStep;
1000
1004
  const current = steps[index];
1001
1005
  const isLast = index === steps.length - 1;
@@ -1325,10 +1329,10 @@ function UpdateBanner({
1325
1329
  buttonLabel = "Refresh now",
1326
1330
  className
1327
1331
  }) {
1328
- const [show, setShow] = React35.useState(forceShow);
1329
- const [entered, setEntered] = React35.useState(false);
1330
- const [refreshing, setRefreshing] = React35.useState(false);
1331
- React35.useEffect(() => {
1332
+ const [show, setShow] = React20.useState(forceShow);
1333
+ const [entered, setEntered] = React20.useState(false);
1334
+ const [refreshing, setRefreshing] = React20.useState(false);
1335
+ React20.useEffect(() => {
1332
1336
  if (forceShow) {
1333
1337
  setShow(true);
1334
1338
  return;
@@ -1351,7 +1355,7 @@ function UpdateBanner({
1351
1355
  clearInterval(id);
1352
1356
  };
1353
1357
  }, [currentVersion, fetchVersion, forceShow, intervalMs]);
1354
- React35.useEffect(() => {
1358
+ React20.useEffect(() => {
1355
1359
  if (!show) {
1356
1360
  setEntered(false);
1357
1361
  return;
@@ -1424,9 +1428,9 @@ function FadeIn({
1424
1428
  style,
1425
1429
  ...props
1426
1430
  }) {
1427
- const ref = React35.useRef(null);
1428
- const [visible, setVisible] = React35.useState(false);
1429
- React35.useEffect(() => {
1431
+ const ref = React20.useRef(null);
1432
+ const [visible, setVisible] = React20.useState(false);
1433
+ React20.useEffect(() => {
1430
1434
  const el = ref.current;
1431
1435
  if (!el) return;
1432
1436
  const observer = new IntersectionObserver(
@@ -1621,16 +1625,16 @@ function Carousel({
1621
1625
  className
1622
1626
  }) {
1623
1627
  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(() => {
1628
+ const trackRef = React20.useRef(null);
1629
+ const [canPrev, setCanPrev] = React20.useState(false);
1630
+ const [canNext, setCanNext] = React20.useState(true);
1631
+ const updateScrollState = React20.useCallback(() => {
1628
1632
  const track = trackRef.current;
1629
1633
  if (!track) return;
1630
1634
  setCanPrev(track.scrollLeft > 8);
1631
1635
  setCanNext(track.scrollLeft < track.scrollWidth - track.clientWidth - 8);
1632
1636
  }, []);
1633
- React35.useEffect(() => {
1637
+ React20.useEffect(() => {
1634
1638
  const track = trackRef.current;
1635
1639
  if (!track) return;
1636
1640
  updateScrollState();
@@ -1687,7 +1691,7 @@ function Carousel({
1687
1691
  role: "region",
1688
1692
  "aria-label": ariaLabel,
1689
1693
  className: "flex snap-x snap-mandatory gap-6 overflow-x-auto pb-4 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
1690
- children: React35.Children.map(
1694
+ children: React20.Children.map(
1691
1695
  children,
1692
1696
  (child) => child == null ? null : /* @__PURE__ */ jsx("div", { "data-carousel-item": true, className: cn$1("shrink-0 snap-start", itemClassName), children: child })
1693
1697
  )
@@ -1712,9 +1716,9 @@ function StaggerChildren({
1712
1716
  className,
1713
1717
  ...props
1714
1718
  }) {
1715
- const ref = React35.useRef(null);
1716
- const [visible, setVisible] = React35.useState(false);
1717
- React35.useEffect(() => {
1719
+ const ref = React20.useRef(null);
1720
+ const [visible, setVisible] = React20.useState(false);
1721
+ React20.useEffect(() => {
1718
1722
  const el = ref.current;
1719
1723
  if (!el) return;
1720
1724
  const observer = new IntersectionObserver(
@@ -1732,7 +1736,7 @@ function StaggerChildren({
1732
1736
  return () => observer.disconnect();
1733
1737
  }, [once]);
1734
1738
  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(
1739
+ return /* @__PURE__ */ jsx("div", { ref, className: cn$1(className), ...props, children: React20.Children.map(children, (child, i) => /* @__PURE__ */ jsx(
1736
1740
  "div",
1737
1741
  {
1738
1742
  className: "h-full",
@@ -1874,7 +1878,7 @@ function StepsSection({
1874
1878
  /* @__PURE__ */ jsx("div", { className: "mt-12", children: resolvedGroups.map((group, groupIndex) => {
1875
1879
  const startNumber = nextNumber;
1876
1880
  nextNumber += group.steps.length;
1877
- return /* @__PURE__ */ jsxs(React35.Fragment, { children: [
1881
+ return /* @__PURE__ */ jsxs(React20.Fragment, { children: [
1878
1882
  /* @__PURE__ */ jsx("div", { className: cn$1(groupIndex > 0 && "mt-10"), children: /* @__PURE__ */ jsx(TimelineGroup, { steps: group.steps, startNumber, fadeIn: groupIndex > 0 }) }),
1879
1883
  group.after && /* @__PURE__ */ jsx("div", { className: "mt-16", children: group.after })
1880
1884
  ] }, groupIndex);
@@ -2044,9 +2048,9 @@ function FeatureMarqueeSection({
2044
2048
  ] });
2045
2049
  }
2046
2050
  function useIntersectionObserver(options) {
2047
- const ref = React35.useRef(null);
2048
- const [isIntersecting, setIsIntersecting] = React35.useState(false);
2049
- React35.useEffect(() => {
2051
+ const ref = React20.useRef(null);
2052
+ const [isIntersecting, setIsIntersecting] = React20.useState(false);
2053
+ React20.useEffect(() => {
2050
2054
  const el = ref.current;
2051
2055
  if (!el) return;
2052
2056
  const observer = new IntersectionObserver(([entry]) => {
@@ -2068,8 +2072,8 @@ function ShowcaseCta({
2068
2072
  sectionClasses
2069
2073
  }) {
2070
2074
  const [ref, intersecting] = useIntersectionObserver({ threshold: 0.15 });
2071
- const [visible, setVisible] = React35.useState(false);
2072
- React35.useEffect(() => {
2075
+ const [visible, setVisible] = React20.useState(false);
2076
+ React20.useEffect(() => {
2073
2077
  if (intersecting) setVisible(true);
2074
2078
  }, [intersecting]);
2075
2079
  return /* @__PURE__ */ jsxs(
@@ -2153,6 +2157,122 @@ function CtaSection(props) {
2153
2157
  ] }) })
2154
2158
  ] }) });
2155
2159
  }
2160
+ var EFFECTS = {
2161
+ // Odometer. No opacity at all — the two values are solid and one physically
2162
+ // displaces the other, which is what makes it read as a mechanism rather
2163
+ // than a crossfade. Needs `clip`, or the departing value is legible above
2164
+ // the container the whole way out.
2165
+ roll: {
2166
+ clip: true,
2167
+ duration: 320,
2168
+ easing: "cubic-bezier(0.22, 1, 0.36, 1)",
2169
+ enter: { from: { transform: "translateY(100%)" }, to: { transform: "translateY(0)" } },
2170
+ exit: { from: { transform: "translateY(0)" }, to: { transform: "translateY(-100%)" } }
2171
+ },
2172
+ // The neutral one. No movement, so it never fights a layout that's also
2173
+ // reflowing around it.
2174
+ fade: {
2175
+ clip: false,
2176
+ duration: 220,
2177
+ easing: "ease",
2178
+ enter: { from: { opacity: 0 }, to: { opacity: 1 } },
2179
+ exit: { from: { opacity: 1 }, to: { opacity: 0 } }
2180
+ },
2181
+ // Horizontal, and short: 0.75rem of travel carried by opacity, so it needs
2182
+ // no clipping and won't crop a ring or drop shadow on whatever it wraps.
2183
+ slide: {
2184
+ clip: false,
2185
+ duration: 280,
2186
+ easing: "cubic-bezier(0.4, 0, 0.2, 1)",
2187
+ enter: {
2188
+ from: { opacity: 0, transform: "translateX(0.75rem)" },
2189
+ to: { opacity: 1, transform: "translateX(0)" }
2190
+ },
2191
+ exit: {
2192
+ from: { opacity: 1, transform: "translateX(0)" },
2193
+ to: { opacity: 0, transform: "translateX(-0.75rem)" }
2194
+ }
2195
+ }
2196
+ };
2197
+ var MODE_EFFECT = {
2198
+ default: "fade",
2199
+ playful: "roll",
2200
+ smooth: "slide"
2201
+ };
2202
+ function AnimatedSwap({
2203
+ swapKey,
2204
+ effect,
2205
+ duration,
2206
+ children,
2207
+ className,
2208
+ style,
2209
+ ...props
2210
+ }) {
2211
+ const mode = useUIMode();
2212
+ const resolved = effect ?? MODE_EFFECT[mode];
2213
+ const spec = typeof resolved !== "string" ? resolved : resolved === "none" ? null : EFFECTS[resolved];
2214
+ const ms = duration ?? spec?.duration ?? 0;
2215
+ const reduced = usePrefersReducedMotion();
2216
+ const animated = spec !== null && !reduced;
2217
+ const previous = React20.useRef(children);
2218
+ const seenKey = React20.useRef(swapKey);
2219
+ const [swap, setSwap] = React20.useState(null);
2220
+ if (seenKey.current !== swapKey) {
2221
+ const out = previous.current;
2222
+ seenKey.current = swapKey;
2223
+ if (animated) setSwap({ key: swapKey, out, running: false });
2224
+ }
2225
+ React20.useEffect(() => {
2226
+ previous.current = children;
2227
+ });
2228
+ React20.useEffect(() => {
2229
+ if (!swap || swap.running) return;
2230
+ const raf = requestAnimationFrame(() => {
2231
+ setSwap((s) => s && s.key === swap.key ? { ...s, running: true } : s);
2232
+ });
2233
+ return () => cancelAnimationFrame(raf);
2234
+ }, [swap]);
2235
+ React20.useEffect(() => {
2236
+ if (!swap?.running) return;
2237
+ const done = setTimeout(() => {
2238
+ setSwap((s) => s && s.key === swap.key ? null : s);
2239
+ }, ms);
2240
+ return () => clearTimeout(done);
2241
+ }, [swap, ms]);
2242
+ const phase = (layer) => {
2243
+ if (!swap || !spec) return void 0;
2244
+ return {
2245
+ ...spec[layer][swap.running ? "to" : "from"],
2246
+ transition: `transform ${ms}ms ${spec.easing}, opacity ${ms}ms ${spec.easing}`
2247
+ };
2248
+ };
2249
+ return /* @__PURE__ */ jsxs(
2250
+ "span",
2251
+ {
2252
+ className: cn$1("relative inline-block", swap && spec?.clip && "overflow-hidden", className),
2253
+ style,
2254
+ ...props,
2255
+ children: [
2256
+ /* @__PURE__ */ jsx("span", { className: "block", style: phase("enter"), children }),
2257
+ swap && // Pinned rather than inset-0: stretching the outgoing copy to the
2258
+ // incoming one's box would resize it mid-exit.
2259
+ /* @__PURE__ */ jsx("span", { className: "absolute left-0 top-0 block", "aria-hidden": "true", style: phase("exit"), children: swap.out })
2260
+ ]
2261
+ }
2262
+ );
2263
+ }
2264
+ function usePrefersReducedMotion() {
2265
+ const [reduced, setReduced] = React20.useState(false);
2266
+ React20.useEffect(() => {
2267
+ const query = window.matchMedia?.("(prefers-reduced-motion: reduce)");
2268
+ if (!query) return;
2269
+ setReduced(query.matches);
2270
+ const onChange = (e) => setReduced(e.matches);
2271
+ query.addEventListener("change", onChange);
2272
+ return () => query.removeEventListener("change", onChange);
2273
+ }, []);
2274
+ return reduced;
2275
+ }
2156
2276
  function PricingCard({
2157
2277
  name,
2158
2278
  price,
@@ -2186,7 +2306,7 @@ function PricingCard({
2186
2306
  /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
2187
2307
  /* @__PURE__ */ jsx("div", { className: "text-sm font-medium text-muted-foreground", children: name }),
2188
2308
  /* @__PURE__ */ jsxs("div", { className: "flex items-end gap-1", children: [
2189
- /* @__PURE__ */ jsx("span", { className: "text-4xl font-bold tracking-tight", children: price }),
2309
+ /* @__PURE__ */ jsx(AnimatedSwap, { swapKey: price, className: "text-4xl font-bold tracking-tight", children: price }),
2190
2310
  /* @__PURE__ */ jsx("span", { className: "mb-1 text-sm text-muted-foreground", children: period })
2191
2311
  ] }),
2192
2312
  /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: description })
@@ -2246,8 +2366,8 @@ function CountdownTimer({
2246
2366
  className,
2247
2367
  compact = false
2248
2368
  }) {
2249
- const [timeLeft, setTimeLeft] = React35.useState(() => getTimeLeft(deadline));
2250
- React35.useEffect(() => {
2369
+ const [timeLeft, setTimeLeft] = React20.useState(() => getTimeLeft(deadline));
2370
+ React20.useEffect(() => {
2251
2371
  setTimeLeft(getTimeLeft(deadline));
2252
2372
  const id = setInterval(() => setTimeLeft(getTimeLeft(deadline)), 1e3);
2253
2373
  return () => clearInterval(id);
@@ -2273,7 +2393,7 @@ function CountdownTimer({
2273
2393
  ];
2274
2394
  return /* @__PURE__ */ jsxs("div", { className: cn$1("flex items-center justify-center gap-2 text-sm", className), children: [
2275
2395
  /* @__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: [
2396
+ /* @__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
2397
  /* @__PURE__ */ jsxs("span", { children: [
2278
2398
  String(value).padStart(2, "0"),
2279
2399
  /* @__PURE__ */ jsx("span", { className: "font-normal text-muted-foreground", children: unit })
@@ -2328,13 +2448,13 @@ function PricingSection({
2328
2448
  onSelectPlan,
2329
2449
  pendingPlanName
2330
2450
  }) {
2331
- const [annual, setAnnual] = React35.useState(false);
2451
+ const [annual, setAnnual] = React20.useState(false);
2332
2452
  const isOneTime = mode === "one-time";
2333
2453
  const useCadences = !!cadences?.length;
2334
2454
  const initialCadence = (defaultCadence && cadences?.some((c) => c.key === defaultCadence) ? defaultCadence : null) ?? cadences?.[0]?.key ?? "";
2335
- const [activeCadence, setActiveCadence] = React35.useState(initialCadence);
2455
+ const [activeCadence, setActiveCadence] = React20.useState(initialCadence);
2336
2456
  const cadence = cadences?.find((c) => c.key === activeCadence);
2337
- const saveBadges = React35.useMemo(
2457
+ const saveBadges = React20.useMemo(
2338
2458
  () => useCadences ? computeSaveBadges(plans, cadences, initialCadence) : {},
2339
2459
  [useCadences, plans, cadences, initialCadence]
2340
2460
  );
@@ -2628,10 +2748,10 @@ function CountUp({
2628
2748
  className,
2629
2749
  ...props
2630
2750
  }) {
2631
- const ref = React35.useRef(null);
2632
- const [value, setValue] = React35.useState(from);
2633
- const hasStarted = React35.useRef(false);
2634
- React35.useEffect(() => {
2751
+ const ref = React20.useRef(null);
2752
+ const [value, setValue] = React20.useState(from);
2753
+ const hasStarted = React20.useRef(false);
2754
+ React20.useEffect(() => {
2635
2755
  const el = ref.current;
2636
2756
  if (!el) return;
2637
2757
  const observer = new IntersectionObserver(
@@ -2724,8 +2844,8 @@ function NewsletterSection({
2724
2844
  successDescription = defaults.successDescription,
2725
2845
  onSubscribe
2726
2846
  } = {}) {
2727
- const [email, setEmail] = React35.useState("");
2728
- const [submitted, setSubmitted] = React35.useState(false);
2847
+ const [email, setEmail] = React20.useState("");
2848
+ const [submitted, setSubmitted] = React20.useState(false);
2729
2849
  const mode = useUIVariant();
2730
2850
  const sectionClasses = cn$1(
2731
2851
  "overflow-hidden bg-card",
@@ -2816,7 +2936,7 @@ function ContactSection({
2816
2936
  sendAnotherLabel = defaults2.sendAnotherLabel,
2817
2937
  onSubmit
2818
2938
  } = {}) {
2819
- const [submitted, setSubmitted] = React35.useState(false);
2939
+ const [submitted, setSubmitted] = React20.useState(false);
2820
2940
  const mode = useUIVariant();
2821
2941
  const sectionClasses = cn$1(
2822
2942
  "overflow-hidden bg-card",
@@ -3114,10 +3234,10 @@ function Navbar({
3114
3234
  controls,
3115
3235
  renderLink = defaultRenderLink7
3116
3236
  }) {
3117
- const [open, setOpen] = React35.useState(false);
3237
+ const [open, setOpen] = React20.useState(false);
3118
3238
  const brandHref = brand.href ?? "/";
3119
3239
  const hasRightContent = controls?.length || cta?.primary || cta?.secondary;
3120
- const closeMobileMenu = React35.useCallback(() => setOpen(false), []);
3240
+ const closeMobileMenu = React20.useCallback(() => setOpen(false), []);
3121
3241
  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
3242
  renderLink({
3123
3243
  href: brandHref,
@@ -3132,7 +3252,7 @@ function Navbar({
3132
3252
  children: link.label
3133
3253
  }) }, link.label)) }),
3134
3254
  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)),
3255
+ controls?.map((control, i) => /* @__PURE__ */ jsx(React20.Fragment, { children: control }, i)),
3136
3256
  (cta?.secondary || cta?.primary) && controls?.length ? /* @__PURE__ */ jsx("div", { className: "mx-1 h-4 w-px bg-border" }) : null,
3137
3257
  cta?.secondary && renderLink({
3138
3258
  href: cta.secondary.href,
@@ -3156,7 +3276,7 @@ function Navbar({
3156
3276
  /* @__PURE__ */ jsx("span", { children: brand.name })
3157
3277
  ] })
3158
3278
  }) }) }),
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,
3279
+ 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
3280
  /* @__PURE__ */ jsx(Separator, {}),
3161
3281
  /* @__PURE__ */ jsx("nav", { className: "mt-4 flex flex-col gap-1", children: navLinks.map((link) => /* @__PURE__ */ jsx("span", { onClickCapture: closeMobileMenu, children: renderLink({
3162
3282
  href: link.href,
@@ -3305,7 +3425,7 @@ function LogoStrip({
3305
3425
  ] });
3306
3426
  }
3307
3427
  function GridUnderlay({ variant, size = 24, className, ...props }) {
3308
- const id = React35.useId();
3428
+ const id = React20.useId();
3309
3429
  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
3430
  /* @__PURE__ */ jsx("line", { x1: size / 2, y1: 0, x2: size / 2, y2: size, stroke: "currentColor", strokeWidth: 0.5 }),
3311
3431
  /* @__PURE__ */ jsx("line", { x1: 0, y1: size / 2, x2: size, y2: size / 2, stroke: "currentColor", strokeWidth: 0.5 })
@@ -3333,9 +3453,9 @@ function GlowUnderlay({
3333
3453
  style,
3334
3454
  ...props
3335
3455
  }) {
3336
- const [pos, setPos] = React35.useState({ x: "50%", y: "50%" });
3337
- const containerRef = React35.useRef(null);
3338
- React35.useEffect(() => {
3456
+ const [pos, setPos] = React20.useState({ x: "50%", y: "50%" });
3457
+ const containerRef = React20.useRef(null);
3458
+ React20.useEffect(() => {
3339
3459
  if (!followCursor) return;
3340
3460
  const handleMouseMove = (e) => {
3341
3461
  const el = containerRef.current;
@@ -3474,8 +3594,8 @@ function PageTransition({
3474
3594
  style,
3475
3595
  ...props
3476
3596
  }) {
3477
- const [mounted, setMounted] = React35.useState(false);
3478
- React35.useEffect(() => {
3597
+ const [mounted, setMounted] = React20.useState(false);
3598
+ React20.useEffect(() => {
3479
3599
  const id = requestAnimationFrame(() => setMounted(true));
3480
3600
  return () => cancelAnimationFrame(id);
3481
3601
  }, []);
@@ -3550,7 +3670,7 @@ function Sortable({
3550
3670
  if (oldIndex === -1 || newIndex === -1) return;
3551
3671
  onReorder(arrayMove(items, oldIndex, newIndex));
3552
3672
  };
3553
- const childArray = React35.Children.toArray(children);
3673
+ const childArray = React20.Children.toArray(children);
3554
3674
  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
3675
  (child, i) => items[i] === void 0 ? null : /* @__PURE__ */ jsx(SortableItem, { id: items[i], disabled, className: itemClassName, children: child }, items[i])
3556
3676
  ) }) }) });
@@ -3562,8 +3682,8 @@ function Spotlight({
3562
3682
  triggerClassName,
3563
3683
  shortcut = "\u2318K"
3564
3684
  }) {
3565
- const [open, setOpen] = React35.useState(false);
3566
- React35.useEffect(() => {
3685
+ const [open, setOpen] = React20.useState(false);
3686
+ React20.useEffect(() => {
3567
3687
  const down = (e) => {
3568
3688
  if (e.key === "k" && (e.metaKey || e.ctrlKey)) {
3569
3689
  e.preventDefault();
@@ -3593,7 +3713,7 @@ function Spotlight({
3593
3713
  /* @__PURE__ */ jsx(CommandInput, { placeholder }),
3594
3714
  /* @__PURE__ */ jsxs(CommandList, { children: [
3595
3715
  /* @__PURE__ */ jsx(CommandEmpty, { children: "No results found." }),
3596
- groups.map((group, i) => /* @__PURE__ */ jsxs(React35.Fragment, { children: [
3716
+ groups.map((group, i) => /* @__PURE__ */ jsxs(React20.Fragment, { children: [
3597
3717
  i > 0 && /* @__PURE__ */ jsx(CommandSeparator, {}),
3598
3718
  /* @__PURE__ */ jsx(CommandGroup, { heading: group.heading, children: group.items.map((item) => /* @__PURE__ */ jsxs(
3599
3719
  CommandItem,
@@ -3618,8 +3738,8 @@ function Spotlight({
3618
3738
  var BASE = 40;
3619
3739
  var MAGNIFY_RADIUS = 80;
3620
3740
  function Dock({ items, iconSize = BASE, magnification = 1.7, className, ...props }) {
3621
- const [mouseX, setMouseX] = React35.useState(null);
3622
- const containerRef = React35.useRef(null);
3741
+ const [mouseX, setMouseX] = React20.useState(null);
3742
+ const containerRef = React20.useRef(null);
3623
3743
  function getScale(index) {
3624
3744
  if (mouseX === null || !containerRef.current) return 1;
3625
3745
  const container = containerRef.current;
@@ -3718,7 +3838,7 @@ function ConfirmDialog({ isOpen, options, handleConfirm, handleCancel, destructi
3718
3838
  ] }) });
3719
3839
  }
3720
3840
  function RegisterHotkeys({ hotkeys }) {
3721
- React35.useEffect(() => {
3841
+ React20.useEffect(() => {
3722
3842
  const handleKeyDown = (event) => {
3723
3843
  for (const hotkey of hotkeys) {
3724
3844
  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 +3855,10 @@ function RegisterHotkeys({ hotkeys }) {
3735
3855
  return null;
3736
3856
  }
3737
3857
  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), []);
3858
+ const [isOpen, setIsOpen] = React20.useState(defaultOpen);
3859
+ const open = React20.useCallback(() => setIsOpen(true), []);
3860
+ const close = React20.useCallback(() => setIsOpen(false), []);
3861
+ const toggle = React20.useCallback(() => setIsOpen((prev) => !prev), []);
3742
3862
  return { isOpen, open, close, toggle, setIsOpen };
3743
3863
  }
3744
3864
  function CommandMenu({
@@ -3751,7 +3871,7 @@ function CommandMenu({
3751
3871
  }) {
3752
3872
  const internal = useControlledOpen(false);
3753
3873
  const isOpen = openProp ?? internal.isOpen;
3754
- const setOpen = React35.useCallback(
3874
+ const setOpen = React20.useCallback(
3755
3875
  (next) => {
3756
3876
  if (openProp === void 0) internal.setIsOpen(next);
3757
3877
  onOpenChange?.(next);
@@ -3776,7 +3896,7 @@ function CommandMenu({
3776
3896
  /* @__PURE__ */ jsx(CommandInput, { placeholder }),
3777
3897
  /* @__PURE__ */ jsxs(CommandList, { children: [
3778
3898
  /* @__PURE__ */ jsx(CommandEmpty, { children: emptyMessage }),
3779
- groups.map((group, i) => /* @__PURE__ */ jsxs(React35.Fragment, { children: [
3899
+ groups.map((group, i) => /* @__PURE__ */ jsxs(React20.Fragment, { children: [
3780
3900
  i > 0 && /* @__PURE__ */ jsx(CommandSeparator, {}),
3781
3901
  /* @__PURE__ */ jsx(CommandGroup, { heading: group.heading, children: group.items.map((item) => /* @__PURE__ */ jsxs(
3782
3902
  CommandItem,
@@ -3831,7 +3951,7 @@ function DataView({
3831
3951
  }
3832
3952
  );
3833
3953
  }
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))) });
3954
+ 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
3955
  }
3836
3956
  var TOKEN_COLORS = ["var(--chart-1)", "var(--chart-2)", "var(--chart-3)", "var(--chart-4)", "var(--chart-5)"];
3837
3957
  var seriesColor = (s, i) => s.color ?? TOKEN_COLORS[i % TOKEN_COLORS.length];
@@ -4005,20 +4125,20 @@ function FileUpload({
4005
4125
  hint,
4006
4126
  className
4007
4127
  }) {
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);
4128
+ const [internalFiles, setInternalFiles] = React20.useState(defaultFiles ?? []);
4129
+ const [isDragging, setIsDragging] = React20.useState(false);
4130
+ const [validationError, setValidationError] = React20.useState(null);
4131
+ const inputRef = React20.useRef(null);
4132
+ const dragDepth = React20.useRef(0);
4013
4133
  const files = filesProp ?? internalFiles;
4014
- const setFiles = React35.useCallback(
4134
+ const setFiles = React20.useCallback(
4015
4135
  (next) => {
4016
4136
  if (!filesProp) setInternalFiles(next);
4017
4137
  onFilesChange?.(next);
4018
4138
  },
4019
4139
  [filesProp, onFilesChange]
4020
4140
  );
4021
- const acceptList = React35.useMemo(
4141
+ const acceptList = React20.useMemo(
4022
4142
  () => accept?.split(",").map((a) => a.trim().toLowerCase()).filter(Boolean) ?? [],
4023
4143
  [accept]
4024
4144
  );
@@ -4742,7 +4862,7 @@ function PageHeader({
4742
4862
  return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-1 pb-6", className), children: [
4743
4863
  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
4864
  const isLast = i === breadcrumbs.length - 1;
4745
- return /* @__PURE__ */ jsxs(React35.Fragment, { children: [
4865
+ return /* @__PURE__ */ jsxs(React20.Fragment, { children: [
4746
4866
  i > 0 && /* @__PURE__ */ jsx(ChevronRight, { className: "size-3.5 shrink-0" }),
4747
4867
  isLast || !crumb.href ? /* @__PURE__ */ jsx("span", { className: cn(isLast && "text-foreground font-medium"), children: crumb.label }) : renderLink({
4748
4868
  href: crumb.href,
@@ -4778,7 +4898,7 @@ function PageHeader({
4778
4898
  ] });
4779
4899
  }
4780
4900
  function Suspensed({ children, fallback }) {
4781
- return /* @__PURE__ */ jsx(React35.Suspense, { fallback: fallback ?? /* @__PURE__ */ jsx(Spinner, {}), children });
4901
+ return /* @__PURE__ */ jsx(React20.Suspense, { fallback: fallback ?? /* @__PURE__ */ jsx(Spinner, {}), children });
4782
4902
  }
4783
4903
  function getInitialTheme() {
4784
4904
  if (typeof document === "undefined") return "dark";
@@ -4786,7 +4906,7 @@ function getInitialTheme() {
4786
4906
  return stored ?? (document.documentElement.classList.contains("dark") ? "dark" : "light");
4787
4907
  }
4788
4908
  function ThemeSwitchMinimal() {
4789
- const [theme, setThemeState] = React35.useState(getInitialTheme);
4909
+ const [theme, setThemeState] = React20.useState(getInitialTheme);
4790
4910
  const toggle = () => {
4791
4911
  const next = theme === "dark" ? "light" : "dark";
4792
4912
  setThemeState(next);
@@ -4912,9 +5032,9 @@ function getInitialColorName() {
4912
5032
  return localStorage.getItem(STORAGE_KEY) ?? "emerald";
4913
5033
  }
4914
5034
  function BrandColorSwitchMinimal() {
4915
- const [active, setActive] = React35.useState(getInitialColorName);
4916
- const [open, setOpen] = React35.useState(false);
4917
- React35.useEffect(() => {
5035
+ const [active, setActive] = React20.useState(getInitialColorName);
5036
+ const [open, setOpen] = React20.useState(false);
5037
+ React20.useEffect(() => {
4918
5038
  const saved = localStorage.getItem(STORAGE_KEY) ?? "emerald";
4919
5039
  const color = BRAND_COLORS.find((c) => c.name === saved);
4920
5040
  if (color) applyColor(color);
@@ -4975,7 +5095,7 @@ function BrandColorSwitchMinimal() {
4975
5095
  ] });
4976
5096
  }
4977
5097
  function ThemeColorUpdater({ colorTheme }) {
4978
- React35.useEffect(() => {
5098
+ React20.useEffect(() => {
4979
5099
  if (colorTheme) {
4980
5100
  document.documentElement.setAttribute("data-theme", colorTheme);
4981
5101
  } else {
@@ -4985,7 +5105,7 @@ function ThemeColorUpdater({ colorTheme }) {
4985
5105
  return null;
4986
5106
  }
4987
5107
  function VersionBanner({ version, message, className, onDismiss }) {
4988
- const [dismissed, setDismissed] = React35.useState(false);
5108
+ const [dismissed, setDismissed] = React20.useState(false);
4989
5109
  if (dismissed) return null;
4990
5110
  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
5111
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
@@ -5242,29 +5362,29 @@ function useMounted() {
5242
5362
  return mounted;
5243
5363
  }
5244
5364
  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 = {}) => {
5365
+ const [isOpen, setIsOpen] = React20.useState(false);
5366
+ const [options, setOptions] = React20.useState({});
5367
+ const resolveRef = React20.useRef(null);
5368
+ const confirm = React20.useCallback((opts = {}) => {
5249
5369
  setOptions(opts);
5250
5370
  setIsOpen(true);
5251
5371
  return new Promise((resolve) => {
5252
5372
  resolveRef.current = resolve;
5253
5373
  });
5254
5374
  }, []);
5255
- const handleConfirm = React35.useCallback(() => {
5375
+ const handleConfirm = React20.useCallback(() => {
5256
5376
  resolveRef.current?.(true);
5257
5377
  setIsOpen(false);
5258
5378
  }, []);
5259
- const handleCancel = React35.useCallback(() => {
5379
+ const handleCancel = React20.useCallback(() => {
5260
5380
  resolveRef.current?.(false);
5261
5381
  setIsOpen(false);
5262
5382
  }, []);
5263
5383
  return { confirm, isOpen, options, handleConfirm, handleCancel };
5264
5384
  }
5265
5385
  function useScrolledPast(threshold) {
5266
- const [scrolledPast, setScrolledPast] = React35.useState(false);
5267
- React35.useEffect(() => {
5386
+ const [scrolledPast, setScrolledPast] = React20.useState(false);
5387
+ React20.useEffect(() => {
5268
5388
  const handleScroll = () => {
5269
5389
  setScrolledPast(window.scrollY > threshold);
5270
5390
  };
@@ -5275,28 +5395,28 @@ function useScrolledPast(threshold) {
5275
5395
  return scrolledPast;
5276
5396
  }
5277
5397
  function useCopyToClipboard() {
5278
- const [copied, setCopied] = React35.useState(false);
5279
- const timeoutRef = React35.useRef(void 0);
5280
- const copy = React35.useCallback((text) => {
5398
+ const [copied, setCopied] = React20.useState(false);
5399
+ const timeoutRef = React20.useRef(void 0);
5400
+ const copy = React20.useCallback((text) => {
5281
5401
  navigator.clipboard.writeText(text).then(() => {
5282
5402
  setCopied(true);
5283
5403
  clearTimeout(timeoutRef.current);
5284
5404
  timeoutRef.current = setTimeout(() => setCopied(false), 2e3);
5285
5405
  });
5286
5406
  }, []);
5287
- React35.useEffect(() => () => clearTimeout(timeoutRef.current), []);
5407
+ React20.useEffect(() => () => clearTimeout(timeoutRef.current), []);
5288
5408
  return [copied, copy];
5289
5409
  }
5290
5410
  function useDebounce(value, delay) {
5291
- const [debounced, setDebounced] = React35.useState(value);
5292
- React35.useEffect(() => {
5411
+ const [debounced, setDebounced] = React20.useState(value);
5412
+ React20.useEffect(() => {
5293
5413
  const timer = setTimeout(() => setDebounced(value), delay);
5294
5414
  return () => clearTimeout(timer);
5295
5415
  }, [value, delay]);
5296
5416
  return debounced;
5297
5417
  }
5298
5418
  function useLocalStorage(key, initialValue) {
5299
- const [storedValue, setStoredValue] = React35.useState(() => {
5419
+ const [storedValue, setStoredValue] = React20.useState(() => {
5300
5420
  if (typeof window === "undefined") return initialValue;
5301
5421
  try {
5302
5422
  const item = window.localStorage.getItem(key);
@@ -5305,7 +5425,7 @@ function useLocalStorage(key, initialValue) {
5305
5425
  return initialValue;
5306
5426
  }
5307
5427
  });
5308
- const setValue = React35.useCallback(
5428
+ const setValue = React20.useCallback(
5309
5429
  (value) => {
5310
5430
  try {
5311
5431
  setStoredValue(value);
@@ -5327,11 +5447,11 @@ function useViewMode(key = "view-mode", fallback = "cards") {
5327
5447
  return { view: mounted ? stored : fallback, setView: setStored, ready: mounted };
5328
5448
  }
5329
5449
  function useMediaQuery(query) {
5330
- const [matches, setMatches] = React35.useState(() => {
5450
+ const [matches, setMatches] = React20.useState(() => {
5331
5451
  if (typeof window === "undefined") return false;
5332
5452
  return window.matchMedia(query).matches;
5333
5453
  });
5334
- React35.useEffect(() => {
5454
+ React20.useEffect(() => {
5335
5455
  if (typeof window === "undefined") return;
5336
5456
  const mql = window.matchMedia(query);
5337
5457
  setMatches(mql.matches);
@@ -5342,18 +5462,18 @@ function useMediaQuery(query) {
5342
5462
  return matches;
5343
5463
  }
5344
5464
  function usePagination(total, pageSize) {
5345
- const [page, setPage] = React35.useState(1);
5465
+ const [page, setPage] = React20.useState(1);
5346
5466
  const totalPages = Math.max(1, Math.ceil(total / pageSize));
5347
5467
  const offset = (page - 1) * pageSize;
5348
- const goTo = React35.useCallback(
5468
+ const goTo = React20.useCallback(
5349
5469
  (p) => setPage(Math.min(Math.max(1, p), totalPages)),
5350
5470
  [totalPages]
5351
5471
  );
5352
- const next = React35.useCallback(() => goTo(page + 1), [page, goTo]);
5353
- const prev = React35.useCallback(() => goTo(page - 1), [page, goTo]);
5472
+ const next = React20.useCallback(() => goTo(page + 1), [page, goTo]);
5473
+ const prev = React20.useCallback(() => goTo(page - 1), [page, goTo]);
5354
5474
  return { page, pageSize, totalPages, offset, hasPrev: page > 1, hasNext: page < totalPages, goTo, next, prev };
5355
5475
  }
5356
5476
 
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 };
5477
+ 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
5478
  //# sourceMappingURL=index.js.map
5359
5479
  //# sourceMappingURL=index.js.map