@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.d.ts +53 -1
- package/dist/index.js +258 -132
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/app/AppShell.tsx +31 -3
- package/src/app/AuthSection.tsx +22 -7
- package/src/components/PricingCard.tsx +7 -1
- package/src/index.ts +6 -0
- package/src/motion/AnimatedSwap.tsx +200 -0
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
|
|
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 =
|
|
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] =
|
|
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
|
|
30
|
+
return React20.useContext(OlwibaUIContext);
|
|
31
31
|
}
|
|
32
32
|
function useUIMode() {
|
|
33
|
-
return
|
|
33
|
+
return React20.useContext(OlwibaUIContext).mode;
|
|
34
34
|
}
|
|
35
|
-
var Button =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
473
|
-
|
|
474
|
-
|
|
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] =
|
|
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] =
|
|
698
|
-
const [rowSelection, setRowSelection] =
|
|
699
|
-
const [globalFilter, setGlobalFilter] =
|
|
700
|
-
const allColumns =
|
|
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
|
-
|
|
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] =
|
|
803
|
-
const [role, setRole] =
|
|
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] =
|
|
848
|
-
const columns =
|
|
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 =
|
|
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] =
|
|
997
|
-
const [error, setError] =
|
|
998
|
-
const [pending, setPending] =
|
|
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] =
|
|
1329
|
-
const [entered, setEntered] =
|
|
1330
|
-
const [refreshing, setRefreshing] =
|
|
1331
|
-
|
|
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
|
-
|
|
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 =
|
|
1428
|
-
const [visible, setVisible] =
|
|
1429
|
-
|
|
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 =
|
|
1625
|
-
const [canPrev, setCanPrev] =
|
|
1626
|
-
const [canNext, setCanNext] =
|
|
1627
|
-
const updateScrollState =
|
|
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
|
-
|
|
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:
|
|
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 =
|
|
1716
|
-
const [visible, setVisible] =
|
|
1717
|
-
|
|
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:
|
|
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(
|
|
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 =
|
|
2048
|
-
const [isIntersecting, setIsIntersecting] =
|
|
2049
|
-
|
|
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] =
|
|
2072
|
-
|
|
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(
|
|
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] =
|
|
2250
|
-
|
|
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(
|
|
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] =
|
|
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] =
|
|
2461
|
+
const [activeCadence, setActiveCadence] = React20.useState(initialCadence);
|
|
2336
2462
|
const cadence = cadences?.find((c) => c.key === activeCadence);
|
|
2337
|
-
const saveBadges =
|
|
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 =
|
|
2632
|
-
const [value, setValue] =
|
|
2633
|
-
const hasStarted =
|
|
2634
|
-
|
|
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] =
|
|
2728
|
-
const [submitted, setSubmitted] =
|
|
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] =
|
|
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] =
|
|
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 =
|
|
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(
|
|
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(
|
|
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 =
|
|
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] =
|
|
3337
|
-
const containerRef =
|
|
3338
|
-
|
|
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] =
|
|
3478
|
-
|
|
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 =
|
|
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] =
|
|
3566
|
-
|
|
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(
|
|
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] =
|
|
3622
|
-
const containerRef =
|
|
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
|
-
|
|
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] =
|
|
3739
|
-
const open =
|
|
3740
|
-
const close =
|
|
3741
|
-
const toggle =
|
|
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 =
|
|
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(
|
|
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(
|
|
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] =
|
|
4009
|
-
const [isDragging, setIsDragging] =
|
|
4010
|
-
const [validationError, setValidationError] =
|
|
4011
|
-
const inputRef =
|
|
4012
|
-
const dragDepth =
|
|
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 =
|
|
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 =
|
|
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(
|
|
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(
|
|
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] =
|
|
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] =
|
|
4916
|
-
const [open, setOpen] =
|
|
4917
|
-
|
|
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
|
-
|
|
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] =
|
|
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] =
|
|
5246
|
-
const [options, setOptions] =
|
|
5247
|
-
const resolveRef =
|
|
5248
|
-
const confirm =
|
|
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 =
|
|
5381
|
+
const handleConfirm = React20.useCallback(() => {
|
|
5256
5382
|
resolveRef.current?.(true);
|
|
5257
5383
|
setIsOpen(false);
|
|
5258
5384
|
}, []);
|
|
5259
|
-
const handleCancel =
|
|
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] =
|
|
5267
|
-
|
|
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] =
|
|
5279
|
-
const timeoutRef =
|
|
5280
|
-
const copy =
|
|
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
|
-
|
|
5413
|
+
React20.useEffect(() => () => clearTimeout(timeoutRef.current), []);
|
|
5288
5414
|
return [copied, copy];
|
|
5289
5415
|
}
|
|
5290
5416
|
function useDebounce(value, delay) {
|
|
5291
|
-
const [debounced, setDebounced] =
|
|
5292
|
-
|
|
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] =
|
|
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 =
|
|
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] =
|
|
5456
|
+
const [matches, setMatches] = React20.useState(() => {
|
|
5331
5457
|
if (typeof window === "undefined") return false;
|
|
5332
5458
|
return window.matchMedia(query).matches;
|
|
5333
5459
|
});
|
|
5334
|
-
|
|
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] =
|
|
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 =
|
|
5474
|
+
const goTo = React20.useCallback(
|
|
5349
5475
|
(p) => setPage(Math.min(Math.max(1, p), totalPages)),
|
|
5350
5476
|
[totalPages]
|
|
5351
5477
|
);
|
|
5352
|
-
const next =
|
|
5353
|
-
const prev =
|
|
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
|