@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.d.ts +53 -1
- package/dist/index.js +248 -128
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/app/AppShell.tsx +31 -3
- 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: [
|
|
@@ -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] =
|
|
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] =
|
|
698
|
-
const [rowSelection, setRowSelection] =
|
|
699
|
-
const [globalFilter, setGlobalFilter] =
|
|
700
|
-
const allColumns =
|
|
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
|
-
|
|
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] =
|
|
803
|
-
const [role, setRole] =
|
|
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] =
|
|
848
|
-
const columns =
|
|
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 =
|
|
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] =
|
|
997
|
-
const [error, setError] =
|
|
998
|
-
const [pending, setPending] =
|
|
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] =
|
|
1329
|
-
const [entered, setEntered] =
|
|
1330
|
-
const [refreshing, setRefreshing] =
|
|
1331
|
-
|
|
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
|
-
|
|
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 =
|
|
1428
|
-
const [visible, setVisible] =
|
|
1429
|
-
|
|
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 =
|
|
1625
|
-
const [canPrev, setCanPrev] =
|
|
1626
|
-
const [canNext, setCanNext] =
|
|
1627
|
-
const updateScrollState =
|
|
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
|
-
|
|
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:
|
|
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 =
|
|
1716
|
-
const [visible, setVisible] =
|
|
1717
|
-
|
|
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:
|
|
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(
|
|
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 =
|
|
2048
|
-
const [isIntersecting, setIsIntersecting] =
|
|
2049
|
-
|
|
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] =
|
|
2072
|
-
|
|
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(
|
|
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] =
|
|
2250
|
-
|
|
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(
|
|
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] =
|
|
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] =
|
|
2455
|
+
const [activeCadence, setActiveCadence] = React20.useState(initialCadence);
|
|
2336
2456
|
const cadence = cadences?.find((c) => c.key === activeCadence);
|
|
2337
|
-
const saveBadges =
|
|
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 =
|
|
2632
|
-
const [value, setValue] =
|
|
2633
|
-
const hasStarted =
|
|
2634
|
-
|
|
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] =
|
|
2728
|
-
const [submitted, setSubmitted] =
|
|
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] =
|
|
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] =
|
|
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 =
|
|
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(
|
|
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(
|
|
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 =
|
|
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] =
|
|
3337
|
-
const containerRef =
|
|
3338
|
-
|
|
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] =
|
|
3478
|
-
|
|
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 =
|
|
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] =
|
|
3566
|
-
|
|
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(
|
|
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] =
|
|
3622
|
-
const containerRef =
|
|
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
|
-
|
|
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] =
|
|
3739
|
-
const open =
|
|
3740
|
-
const close =
|
|
3741
|
-
const toggle =
|
|
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 =
|
|
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(
|
|
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(
|
|
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] =
|
|
4009
|
-
const [isDragging, setIsDragging] =
|
|
4010
|
-
const [validationError, setValidationError] =
|
|
4011
|
-
const inputRef =
|
|
4012
|
-
const dragDepth =
|
|
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 =
|
|
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 =
|
|
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(
|
|
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(
|
|
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] =
|
|
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] =
|
|
4916
|
-
const [open, setOpen] =
|
|
4917
|
-
|
|
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
|
-
|
|
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] =
|
|
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] =
|
|
5246
|
-
const [options, setOptions] =
|
|
5247
|
-
const resolveRef =
|
|
5248
|
-
const confirm =
|
|
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 =
|
|
5375
|
+
const handleConfirm = React20.useCallback(() => {
|
|
5256
5376
|
resolveRef.current?.(true);
|
|
5257
5377
|
setIsOpen(false);
|
|
5258
5378
|
}, []);
|
|
5259
|
-
const handleCancel =
|
|
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] =
|
|
5267
|
-
|
|
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] =
|
|
5279
|
-
const timeoutRef =
|
|
5280
|
-
const copy =
|
|
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
|
-
|
|
5407
|
+
React20.useEffect(() => () => clearTimeout(timeoutRef.current), []);
|
|
5288
5408
|
return [copied, copy];
|
|
5289
5409
|
}
|
|
5290
5410
|
function useDebounce(value, delay) {
|
|
5291
|
-
const [debounced, setDebounced] =
|
|
5292
|
-
|
|
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] =
|
|
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 =
|
|
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] =
|
|
5450
|
+
const [matches, setMatches] = React20.useState(() => {
|
|
5331
5451
|
if (typeof window === "undefined") return false;
|
|
5332
5452
|
return window.matchMedia(query).matches;
|
|
5333
5453
|
});
|
|
5334
|
-
|
|
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] =
|
|
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 =
|
|
5468
|
+
const goTo = React20.useCallback(
|
|
5349
5469
|
(p) => setPage(Math.min(Math.max(1, p), totalPages)),
|
|
5350
5470
|
[totalPages]
|
|
5351
5471
|
);
|
|
5352
|
-
const next =
|
|
5353
|
-
const prev =
|
|
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
|