@vllnt/ui 0.1.6 → 0.1.7-canary.2c4792f
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/components/breadcrumb/breadcrumb.js +9 -13
- package/dist/components/carousel/carousel.js +5 -1
- package/dist/components/code-block/code-block.js +69 -66
- package/dist/components/comparison/comparison.js +13 -1
- package/dist/components/cookie-consent/cookie-consent.js +6 -2
- package/dist/components/flow-diagram/use-flow-diagram.js +7 -2
- package/dist/components/horizontal-scroll-row/horizontal-scroll-row.js +66 -0
- package/dist/components/horizontal-scroll-row/index.js +6 -0
- package/dist/components/index.js +8 -0
- package/dist/components/mdx-content/mdx-content.js +23 -12
- package/dist/components/progress-card/progress-card.js +6 -3
- package/dist/components/search-bar/search-bar.js +4 -2
- package/dist/components/sidebar/sidebar.js +1 -1
- package/dist/components/slideshow/slideshow.js +2 -4
- package/dist/components/theme-toggle/theme-toggle.js +3 -5
- package/dist/components/thinking-block/thinking-block.js +5 -1
- package/dist/components/tldr-section/tldr-section.js +11 -2
- package/dist/components/tutorial-card/tutorial-card.js +6 -3
- package/dist/components/view-switcher/index.js +6 -0
- package/dist/components/view-switcher/view-switcher.js +92 -0
- package/dist/index.d.ts +44 -2
- package/dist/index.js +3 -1
- package/dist/lib/use-horizontal-scroll.js +60 -0
- package/dist/lib/use-mounted.js +17 -0
- package/package.json +42 -23
- package/LICENSE +0 -21
|
@@ -1,31 +1,27 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
2
|
import Link from "next/link";
|
|
3
3
|
import { cn } from "../../lib/utils";
|
|
4
|
+
const SEPARATOR_CHARS = {
|
|
5
|
+
arrow: "\u2192",
|
|
6
|
+
chevron: "\u203A",
|
|
7
|
+
slash: "/"
|
|
8
|
+
};
|
|
9
|
+
function SeparatorIcon({ type }) {
|
|
10
|
+
return /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "text-muted-foreground", children: SEPARATOR_CHARS[type] ?? "\u203A" });
|
|
11
|
+
}
|
|
4
12
|
function Breadcrumb({
|
|
5
13
|
className,
|
|
6
14
|
items,
|
|
7
15
|
separator = "chevron",
|
|
8
16
|
variant = "default"
|
|
9
17
|
}) {
|
|
10
|
-
const getSeparator = () => {
|
|
11
|
-
switch (separator) {
|
|
12
|
-
case "chevron":
|
|
13
|
-
return /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "text-muted-foreground", children: "\u203A" });
|
|
14
|
-
case "slash":
|
|
15
|
-
return /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "text-muted-foreground", children: "/" });
|
|
16
|
-
case "arrow":
|
|
17
|
-
return /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "text-muted-foreground", children: "\u2192" });
|
|
18
|
-
default:
|
|
19
|
-
return /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "text-muted-foreground", children: "\u203A" });
|
|
20
|
-
}
|
|
21
|
-
};
|
|
22
18
|
return /* @__PURE__ */ jsx(
|
|
23
19
|
"nav",
|
|
24
20
|
{
|
|
25
21
|
"aria-label": "Breadcrumb",
|
|
26
22
|
className: cn("flex items-center space-x-1 text-sm", className),
|
|
27
23
|
children: items.map((item, index) => /* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
|
|
28
|
-
index > 0 && /* @__PURE__ */ jsx("span", { className: "mx-2", children:
|
|
24
|
+
index > 0 && /* @__PURE__ */ jsx("span", { className: "mx-2", children: /* @__PURE__ */ jsx(SeparatorIcon, { type: separator }) }),
|
|
29
25
|
item.href ? /* @__PURE__ */ jsxs(
|
|
30
26
|
Link,
|
|
31
27
|
{
|
|
@@ -71,11 +71,15 @@ function useCarouselLogic({
|
|
|
71
71
|
if (!api) {
|
|
72
72
|
return;
|
|
73
73
|
}
|
|
74
|
-
onSelect(api);
|
|
75
74
|
api.on("reInit", onSelect);
|
|
76
75
|
api.on("select", onSelect);
|
|
76
|
+
const rafId = requestAnimationFrame(() => {
|
|
77
|
+
onSelect(api);
|
|
78
|
+
});
|
|
77
79
|
return () => {
|
|
78
80
|
api?.off("select", onSelect);
|
|
81
|
+
api?.off("reInit", onSelect);
|
|
82
|
+
cancelAnimationFrame(rafId);
|
|
79
83
|
};
|
|
80
84
|
}, [api, onSelect]);
|
|
81
85
|
return {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useEffect, useState } from "react";
|
|
3
|
+
import { useEffect, useRef, useState } from "react";
|
|
4
4
|
import { Check, Copy } from "lucide-react";
|
|
5
5
|
import { useTheme } from "next-themes";
|
|
6
6
|
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
|
|
@@ -25,6 +25,11 @@ function extractTextFromChildren(children) {
|
|
|
25
25
|
}
|
|
26
26
|
return String(children ?? "");
|
|
27
27
|
}
|
|
28
|
+
function findScrollableParent(element) {
|
|
29
|
+
if (!element) return void 0;
|
|
30
|
+
if (element.scrollHeight > element.clientHeight) return element;
|
|
31
|
+
return findScrollableParent(element.parentElement);
|
|
32
|
+
}
|
|
28
33
|
function CodeBlock({
|
|
29
34
|
children,
|
|
30
35
|
className,
|
|
@@ -32,15 +37,28 @@ function CodeBlock({
|
|
|
32
37
|
showLanguage = false
|
|
33
38
|
}) {
|
|
34
39
|
const [copied, setCopied] = useState(false);
|
|
35
|
-
const [mounted, setMounted] = useState(false);
|
|
36
40
|
const { systemTheme, theme } = useTheme();
|
|
37
|
-
useEffect(() => {
|
|
38
|
-
setMounted(true);
|
|
39
|
-
}, []);
|
|
40
41
|
const resolvedTheme = theme === "system" ? systemTheme : theme;
|
|
41
|
-
const isDark = resolvedTheme
|
|
42
|
+
const isDark = resolvedTheme !== "light";
|
|
42
43
|
const codeStyle = isDark ? oneDark : oneLight;
|
|
43
44
|
const code = extractTextFromChildren(children);
|
|
45
|
+
const scrollRef = useRef(null);
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
const element = scrollRef.current;
|
|
48
|
+
if (!element) return;
|
|
49
|
+
const onWheel = (event) => {
|
|
50
|
+
if (Math.abs(event.deltaY) <= Math.abs(event.deltaX)) return;
|
|
51
|
+
const scrollable = findScrollableParent(element);
|
|
52
|
+
if (scrollable) {
|
|
53
|
+
scrollable.scrollTop += event.deltaY;
|
|
54
|
+
event.preventDefault();
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
element.addEventListener("wheel", onWheel, { passive: false });
|
|
58
|
+
return () => {
|
|
59
|
+
element.removeEventListener("wheel", onWheel);
|
|
60
|
+
};
|
|
61
|
+
}, []);
|
|
44
62
|
const handleCopy = async () => {
|
|
45
63
|
await navigator.clipboard.writeText(code);
|
|
46
64
|
setCopied(true);
|
|
@@ -48,33 +66,6 @@ function CodeBlock({
|
|
|
48
66
|
setCopied(false);
|
|
49
67
|
}, 2e3);
|
|
50
68
|
};
|
|
51
|
-
if (!mounted) {
|
|
52
|
-
return /* @__PURE__ */ jsx(
|
|
53
|
-
"div",
|
|
54
|
-
{
|
|
55
|
-
className: cn(
|
|
56
|
-
"relative w-full overflow-hidden rounded-md border bg-background",
|
|
57
|
-
className
|
|
58
|
-
),
|
|
59
|
-
children: /* @__PURE__ */ jsxs("div", { className: "relative overflow-x-auto", children: [
|
|
60
|
-
/* @__PURE__ */ jsx("pre", { className: "p-4 text-sm font-mono bg-background", children: /* @__PURE__ */ jsx("code", { children: code }) }),
|
|
61
|
-
/* @__PURE__ */ jsxs("div", { className: "absolute right-2 top-2 flex items-center gap-2", children: [
|
|
62
|
-
showLanguage ? /* @__PURE__ */ jsx("span", { className: "text-xs font-mono text-muted-foreground uppercase tracking-wider", children: language }) : null,
|
|
63
|
-
/* @__PURE__ */ jsx(
|
|
64
|
-
Button,
|
|
65
|
-
{
|
|
66
|
-
className: "h-8 w-8",
|
|
67
|
-
onClick: handleCopy,
|
|
68
|
-
size: "icon",
|
|
69
|
-
variant: "ghost",
|
|
70
|
-
children: /* @__PURE__ */ jsx(Copy, { className: "h-3 w-3" })
|
|
71
|
-
}
|
|
72
|
-
)
|
|
73
|
-
] })
|
|
74
|
-
] })
|
|
75
|
-
}
|
|
76
|
-
);
|
|
77
|
-
}
|
|
78
69
|
return /* @__PURE__ */ jsx(
|
|
79
70
|
"div",
|
|
80
71
|
{
|
|
@@ -82,39 +73,51 @@ function CodeBlock({
|
|
|
82
73
|
"relative w-full overflow-hidden rounded-md border bg-background",
|
|
83
74
|
className
|
|
84
75
|
),
|
|
85
|
-
children: /* @__PURE__ */ jsxs(
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
76
|
+
children: /* @__PURE__ */ jsxs(
|
|
77
|
+
"div",
|
|
78
|
+
{
|
|
79
|
+
className: "relative overflow-x-auto overflow-y-hidden touch-pan-y",
|
|
80
|
+
ref: scrollRef,
|
|
81
|
+
children: [
|
|
82
|
+
/* @__PURE__ */ jsx(
|
|
83
|
+
SyntaxHighlighter,
|
|
84
|
+
{
|
|
85
|
+
codeTagProps: {
|
|
86
|
+
className: "font-mono text-sm",
|
|
87
|
+
style: {
|
|
88
|
+
background: "transparent",
|
|
89
|
+
display: "block"
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
customStyle: {
|
|
93
|
+
background: "hsl(var(--background))",
|
|
94
|
+
fontSize: "0.875rem",
|
|
95
|
+
margin: 0,
|
|
96
|
+
minWidth: "fit-content",
|
|
97
|
+
overflowY: "hidden",
|
|
98
|
+
padding: "1rem"
|
|
99
|
+
},
|
|
100
|
+
language,
|
|
101
|
+
style: codeStyle,
|
|
102
|
+
children: code
|
|
103
|
+
}
|
|
104
|
+
),
|
|
105
|
+
/* @__PURE__ */ jsxs("div", { className: "absolute right-2 top-2 flex items-center gap-2", children: [
|
|
106
|
+
showLanguage ? /* @__PURE__ */ jsx("span", { className: "text-xs font-mono text-muted-foreground uppercase tracking-wider", children: language }) : null,
|
|
107
|
+
/* @__PURE__ */ jsx(
|
|
108
|
+
Button,
|
|
109
|
+
{
|
|
110
|
+
className: "h-8 w-8",
|
|
111
|
+
onClick: handleCopy,
|
|
112
|
+
size: "icon",
|
|
113
|
+
variant: "ghost",
|
|
114
|
+
children: copied ? /* @__PURE__ */ jsx(Check, { className: "h-3 w-3" }) : /* @__PURE__ */ jsx(Copy, { className: "h-3 w-3" })
|
|
115
|
+
}
|
|
116
|
+
)
|
|
117
|
+
] })
|
|
118
|
+
]
|
|
119
|
+
}
|
|
120
|
+
)
|
|
118
121
|
}
|
|
119
122
|
);
|
|
120
123
|
}
|
|
@@ -22,7 +22,19 @@ const variantConfig = {
|
|
|
22
22
|
iconClass: "text-muted-foreground"
|
|
23
23
|
}
|
|
24
24
|
};
|
|
25
|
-
function Comparison({
|
|
25
|
+
function Comparison({
|
|
26
|
+
after,
|
|
27
|
+
before,
|
|
28
|
+
title,
|
|
29
|
+
...rest
|
|
30
|
+
}) {
|
|
31
|
+
if (!before || !after) {
|
|
32
|
+
const hint = "left" in rest || "right" in rest ? ' Did you mean "before" / "after" instead of "left" / "right"?' : "";
|
|
33
|
+
console.error(
|
|
34
|
+
`[Comparison] Missing required props "before" and "after".${hint}`
|
|
35
|
+
);
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
26
38
|
const beforeConfig = variantConfig[before.variant || "bad"];
|
|
27
39
|
const afterConfig = variantConfig[after.variant || "good"];
|
|
28
40
|
const BeforeIcon = beforeConfig.icon;
|
|
@@ -50,9 +50,13 @@ const CookieConsent = forwardRef(
|
|
|
50
50
|
return () => {
|
|
51
51
|
clearTimeout(timer);
|
|
52
52
|
};
|
|
53
|
-
} else {
|
|
54
|
-
setIsVisible(false);
|
|
55
53
|
}
|
|
54
|
+
const rafId = requestAnimationFrame(() => {
|
|
55
|
+
setIsVisible(false);
|
|
56
|
+
});
|
|
57
|
+
return () => {
|
|
58
|
+
cancelAnimationFrame(rafId);
|
|
59
|
+
};
|
|
56
60
|
}, [open]);
|
|
57
61
|
const handleClose = useCallback(() => {
|
|
58
62
|
setIsAnimatingOut(true);
|
|
@@ -25,8 +25,13 @@ function useZoomControls(reactFlow) {
|
|
|
25
25
|
void reactFlow.fitView({ duration: 200, padding: 0.2 });
|
|
26
26
|
}, [reactFlow]);
|
|
27
27
|
useEffect(() => {
|
|
28
|
-
const
|
|
29
|
-
|
|
28
|
+
const rafId = requestAnimationFrame(() => {
|
|
29
|
+
const viewport = reactFlow.getViewport();
|
|
30
|
+
setZoom(viewport.zoom);
|
|
31
|
+
});
|
|
32
|
+
return () => {
|
|
33
|
+
cancelAnimationFrame(rafId);
|
|
34
|
+
};
|
|
30
35
|
}, [reactFlow]);
|
|
31
36
|
return { fitView, zoom, zoomIn, zoomOut };
|
|
32
37
|
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { memo } from "react";
|
|
4
|
+
import { ChevronLeft, ChevronRight } from "lucide-react";
|
|
5
|
+
import { useHorizontalScroll } from "../../lib/use-horizontal-scroll";
|
|
6
|
+
import { cn } from "../../lib/utils";
|
|
7
|
+
import { Button } from "../button/button";
|
|
8
|
+
const HorizontalScrollRow = memo(function HorizontalScrollRow2({
|
|
9
|
+
children,
|
|
10
|
+
className,
|
|
11
|
+
description,
|
|
12
|
+
title
|
|
13
|
+
}) {
|
|
14
|
+
const { canScrollLeft, canScrollRight, containerRef, scroll } = useHorizontalScroll();
|
|
15
|
+
const showControls = canScrollLeft || canScrollRight;
|
|
16
|
+
return /* @__PURE__ */ jsxs("section", { className: cn("space-y-4", className), children: [
|
|
17
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
18
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
19
|
+
/* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold", children: title }),
|
|
20
|
+
description ? /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: description }) : null
|
|
21
|
+
] }),
|
|
22
|
+
showControls ? /* @__PURE__ */ jsxs("div", { className: "flex gap-1", children: [
|
|
23
|
+
/* @__PURE__ */ jsx(
|
|
24
|
+
Button,
|
|
25
|
+
{
|
|
26
|
+
"aria-label": "Scroll left",
|
|
27
|
+
className: "h-8 w-8",
|
|
28
|
+
disabled: !canScrollLeft,
|
|
29
|
+
onClick: () => {
|
|
30
|
+
scroll("left");
|
|
31
|
+
},
|
|
32
|
+
size: "icon",
|
|
33
|
+
variant: "outline",
|
|
34
|
+
children: /* @__PURE__ */ jsx(ChevronLeft, { className: "h-4 w-4" })
|
|
35
|
+
}
|
|
36
|
+
),
|
|
37
|
+
/* @__PURE__ */ jsx(
|
|
38
|
+
Button,
|
|
39
|
+
{
|
|
40
|
+
"aria-label": "Scroll right",
|
|
41
|
+
className: "h-8 w-8",
|
|
42
|
+
disabled: !canScrollRight,
|
|
43
|
+
onClick: () => {
|
|
44
|
+
scroll("right");
|
|
45
|
+
},
|
|
46
|
+
size: "icon",
|
|
47
|
+
variant: "outline",
|
|
48
|
+
children: /* @__PURE__ */ jsx(ChevronRight, { className: "h-4 w-4" })
|
|
49
|
+
}
|
|
50
|
+
)
|
|
51
|
+
] }) : null
|
|
52
|
+
] }),
|
|
53
|
+
/* @__PURE__ */ jsx(
|
|
54
|
+
"div",
|
|
55
|
+
{
|
|
56
|
+
className: "flex gap-4 overflow-x-auto snap-x snap-mandatory [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
|
|
57
|
+
ref: containerRef,
|
|
58
|
+
children
|
|
59
|
+
}
|
|
60
|
+
)
|
|
61
|
+
] });
|
|
62
|
+
});
|
|
63
|
+
HorizontalScrollRow.displayName = "HorizontalScrollRow";
|
|
64
|
+
export {
|
|
65
|
+
HorizontalScrollRow
|
|
66
|
+
};
|
package/dist/components/index.js
CHANGED
|
@@ -340,6 +340,12 @@ import {
|
|
|
340
340
|
SocialFAB,
|
|
341
341
|
useSocialFab
|
|
342
342
|
} from "./social-fab";
|
|
343
|
+
import {
|
|
344
|
+
HorizontalScrollRow
|
|
345
|
+
} from "./horizontal-scroll-row";
|
|
346
|
+
import {
|
|
347
|
+
ViewSwitcher
|
|
348
|
+
} from "./view-switcher";
|
|
343
349
|
import {
|
|
344
350
|
FlowControls,
|
|
345
351
|
FlowDiagram,
|
|
@@ -480,6 +486,7 @@ export {
|
|
|
480
486
|
FlowErrorBoundary,
|
|
481
487
|
FlowFullscreen,
|
|
482
488
|
Glossary,
|
|
489
|
+
HorizontalScrollRow,
|
|
483
490
|
HoverCard,
|
|
484
491
|
HoverCardContent,
|
|
485
492
|
HoverCardTrigger,
|
|
@@ -618,6 +625,7 @@ export {
|
|
|
618
625
|
TutorialIntroContent,
|
|
619
626
|
TutorialMDX,
|
|
620
627
|
VideoEmbed,
|
|
628
|
+
ViewSwitcher,
|
|
621
629
|
alertVariants,
|
|
622
630
|
badgeVariants,
|
|
623
631
|
buttonVariants,
|
|
@@ -21,7 +21,21 @@ const MDXComponents = {
|
|
|
21
21
|
children
|
|
22
22
|
}
|
|
23
23
|
),
|
|
24
|
-
code: ({ children, ...props }) =>
|
|
24
|
+
code: ({ children, className, ...props }) => {
|
|
25
|
+
if (typeof className === "string" && className.startsWith("language-")) {
|
|
26
|
+
const language = className.replace(/^language-/, "");
|
|
27
|
+
const text = typeof children === "string" ? children.replace(/\n$/, "") : String(children ?? "");
|
|
28
|
+
return /* @__PURE__ */ jsx(CodeBlock, { language, children: text });
|
|
29
|
+
}
|
|
30
|
+
return /* @__PURE__ */ jsx(
|
|
31
|
+
"code",
|
|
32
|
+
{
|
|
33
|
+
className: "bg-muted px-1 py-0.5 rounded text-sm font-mono",
|
|
34
|
+
...props,
|
|
35
|
+
children
|
|
36
|
+
}
|
|
37
|
+
);
|
|
38
|
+
},
|
|
25
39
|
em: ({ children, ...props }) => /* @__PURE__ */ jsx("em", { className: "italic", ...props, children }),
|
|
26
40
|
h1: ({ children, ...props }) => /* @__PURE__ */ jsx("h1", { className: "text-2xl font-bold mt-8 mb-4", ...props, children }),
|
|
27
41
|
h2: ({ children, ...props }) => /* @__PURE__ */ jsx("h2", { className: "text-xl font-bold mt-6 mb-3", ...props, children }),
|
|
@@ -51,14 +65,7 @@ const MDXComponents = {
|
|
|
51
65
|
children
|
|
52
66
|
}
|
|
53
67
|
),
|
|
54
|
-
pre: ({ children
|
|
55
|
-
"pre",
|
|
56
|
-
{
|
|
57
|
-
className: "bg-black text-white p-4 rounded-lg overflow-x-auto my-6 border shadow-lg font-mono text-sm dark:bg-zinc-900",
|
|
58
|
-
...props,
|
|
59
|
-
children
|
|
60
|
-
}
|
|
61
|
-
),
|
|
68
|
+
pre: ({ children }) => /* @__PURE__ */ jsx("div", { className: "contents", children }),
|
|
62
69
|
strong: ({ children, ...props }) => /* @__PURE__ */ jsx("strong", { className: "font-semibold", ...props, children }),
|
|
63
70
|
ul: ({ children, ...props }) => /* @__PURE__ */ jsx(
|
|
64
71
|
"ul",
|
|
@@ -122,16 +129,20 @@ async function MDXContent({
|
|
|
122
129
|
const customComponents = buildCustomComponents(components);
|
|
123
130
|
const allComponents = { ...MDXComponents, ...customComponents };
|
|
124
131
|
if (enableMDX && hasJSX) {
|
|
132
|
+
let Component;
|
|
125
133
|
try {
|
|
126
|
-
const
|
|
134
|
+
const result = await evaluate(processedContent, {
|
|
127
135
|
...runtime,
|
|
128
136
|
baseUrl: import.meta.url
|
|
129
137
|
});
|
|
130
|
-
|
|
138
|
+
Component = result.default;
|
|
131
139
|
} catch (error) {
|
|
132
140
|
console.error("Error rendering MDX:", error);
|
|
133
|
-
return /* @__PURE__ */ jsx("div", { className: proseClasses, children: /* @__PURE__ */ jsx(ReactMarkdown, { components: allComponents, children: content }) });
|
|
134
141
|
}
|
|
142
|
+
if (Component) {
|
|
143
|
+
return /* @__PURE__ */ jsx("div", { className: proseClasses, children: /* @__PURE__ */ jsx(Component, { components: allComponents }) });
|
|
144
|
+
}
|
|
145
|
+
return /* @__PURE__ */ jsx("div", { className: proseClasses, children: /* @__PURE__ */ jsx(ReactMarkdown, { components: allComponents, children: content }) });
|
|
135
146
|
}
|
|
136
147
|
return /* @__PURE__ */ jsx("div", { className: proseClasses, children: /* @__PURE__ */ jsx(ReactMarkdown, { components: allComponents, children: content }) });
|
|
137
148
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { memo, useEffect, useState } from "react";
|
|
4
|
+
import { useMounted } from "../../lib/use-mounted";
|
|
4
5
|
import { Badge } from "../badge";
|
|
5
6
|
import {
|
|
6
7
|
Card,
|
|
@@ -29,11 +30,13 @@ function ContentCardImpl({
|
|
|
29
30
|
title
|
|
30
31
|
}) {
|
|
31
32
|
const [progress, setProgress] = useState(null);
|
|
32
|
-
const
|
|
33
|
+
const isHydrated = useMounted();
|
|
33
34
|
useEffect(() => {
|
|
34
|
-
setIsHydrated(true);
|
|
35
35
|
if (getProgress) {
|
|
36
|
-
|
|
36
|
+
const result = getProgress();
|
|
37
|
+
requestAnimationFrame(() => {
|
|
38
|
+
setProgress(result);
|
|
39
|
+
});
|
|
37
40
|
}
|
|
38
41
|
}, [getProgress]);
|
|
39
42
|
const showProgress = isHydrated && progress && progress.completedCount > 0;
|
|
@@ -26,8 +26,10 @@ function SearchBar({
|
|
|
26
26
|
return;
|
|
27
27
|
}
|
|
28
28
|
if (!isUserTyping.current && query !== searchParameter) {
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
requestAnimationFrame(() => {
|
|
30
|
+
setQuery(searchParameter);
|
|
31
|
+
lastDebouncedQueryReference.current = searchParameter;
|
|
32
|
+
});
|
|
31
33
|
}
|
|
32
34
|
}, [searchParameters, query]);
|
|
33
35
|
useEffect(() => {
|
|
@@ -122,7 +122,7 @@ function Sidebar({ sections }) {
|
|
|
122
122
|
"aside",
|
|
123
123
|
{
|
|
124
124
|
className: cn(
|
|
125
|
-
"fixed lg:relative top-16 lg:top-0 left-0 z-40
|
|
125
|
+
"fixed lg:relative top-16 lg:top-0 bottom-0 lg:bottom-auto left-0 z-40 lg:h-full border-r bg-background transition-transform duration-300 ease-in-out",
|
|
126
126
|
"flex flex-col",
|
|
127
127
|
"overflow-hidden",
|
|
128
128
|
"shrink-0",
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { memo, useCallback, useEffect, useState } from "react";
|
|
4
4
|
import { createPortal } from "react-dom";
|
|
5
|
+
import { useMounted } from "../../lib/use-mounted";
|
|
5
6
|
import { cn } from "../../lib/utils";
|
|
6
7
|
import { CompletionDialog } from "../completion-dialog";
|
|
7
8
|
const DEFAULT_LABELS = {
|
|
@@ -31,16 +32,13 @@ function SlideshowImpl({
|
|
|
31
32
|
const [animationDirection, setAnimationDirection] = useState(null);
|
|
32
33
|
const [isCompletionDialogOpen, setIsCompletionDialogOpen] = useState(false);
|
|
33
34
|
const [isTocOpen, setIsTocOpen] = useState(false);
|
|
34
|
-
const
|
|
35
|
+
const mounted = useMounted();
|
|
35
36
|
const currentSection = sections[currentIndex];
|
|
36
37
|
const isCurrentCompleted = currentSection ? completedSections.has(currentSection.id) : false;
|
|
37
38
|
const isLastSection = currentIndex === sections.length - 1;
|
|
38
39
|
const canGoNext = currentIndex < sections.length - 1;
|
|
39
40
|
const canGoPrevious = currentIndex > 0;
|
|
40
41
|
const progress = (currentIndex + 1) / sections.length * 100;
|
|
41
|
-
useEffect(() => {
|
|
42
|
-
setMounted(true);
|
|
43
|
-
}, []);
|
|
44
42
|
useEffect(() => {
|
|
45
43
|
document.body.style.overflow = "hidden";
|
|
46
44
|
return () => {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useCallback,
|
|
3
|
+
import { useCallback, useRef, useState } from "react";
|
|
4
4
|
import { useTheme } from "next-themes";
|
|
5
|
+
import { useMounted } from "../../lib/use-mounted";
|
|
5
6
|
import { Button } from "../button/button";
|
|
6
7
|
import {
|
|
7
8
|
DropdownMenu,
|
|
@@ -51,7 +52,7 @@ function ThemeMenuItem({
|
|
|
51
52
|
}
|
|
52
53
|
function ThemeToggle({ dict }) {
|
|
53
54
|
const { setTheme, theme } = useTheme();
|
|
54
|
-
const
|
|
55
|
+
const mounted = useMounted();
|
|
55
56
|
const [open, setOpen] = useState(false);
|
|
56
57
|
const closeTimerReference = useRef(null);
|
|
57
58
|
const isHoveringOverMenuAreaReference = useRef(false);
|
|
@@ -73,9 +74,6 @@ function ThemeToggle({ dict }) {
|
|
|
73
74
|
}
|
|
74
75
|
setOpen(nextOpen);
|
|
75
76
|
}, []);
|
|
76
|
-
useEffect(() => {
|
|
77
|
-
setMounted(true);
|
|
78
|
-
}, []);
|
|
79
77
|
const getThemeIcon = useCallback(() => {
|
|
80
78
|
if (!mounted) return "\u2600";
|
|
81
79
|
switch (theme) {
|
|
@@ -11,7 +11,11 @@ function ThinkingBlock({
|
|
|
11
11
|
const [isExpanded, setIsExpanded] = useState(isStreaming);
|
|
12
12
|
const contentId = useId();
|
|
13
13
|
useEffect(() => {
|
|
14
|
-
if (isStreaming)
|
|
14
|
+
if (isStreaming) {
|
|
15
|
+
requestAnimationFrame(() => {
|
|
16
|
+
setIsExpanded(true);
|
|
17
|
+
});
|
|
18
|
+
}
|
|
15
19
|
}, [isStreaming]);
|
|
16
20
|
const toggleExpanded = useCallback(() => {
|
|
17
21
|
setIsExpanded((previous) => !previous);
|
|
@@ -8,15 +8,24 @@ function TLDRSection({ children, label }) {
|
|
|
8
8
|
const timerReference = useRef(null);
|
|
9
9
|
useEffect(() => {
|
|
10
10
|
if (isExpanded && !hasBeenOpened) {
|
|
11
|
-
setIsLoading(true);
|
|
12
|
-
setHasBeenOpened(true);
|
|
13
11
|
if (timerReference.current) {
|
|
14
12
|
clearTimeout(timerReference.current);
|
|
15
13
|
}
|
|
14
|
+
const rafId = requestAnimationFrame(() => {
|
|
15
|
+
setIsLoading(true);
|
|
16
|
+
setHasBeenOpened(true);
|
|
17
|
+
});
|
|
16
18
|
timerReference.current = setTimeout(() => {
|
|
17
19
|
setIsLoading(false);
|
|
18
20
|
timerReference.current = null;
|
|
19
21
|
}, 800);
|
|
22
|
+
return () => {
|
|
23
|
+
cancelAnimationFrame(rafId);
|
|
24
|
+
if (timerReference.current) {
|
|
25
|
+
clearTimeout(timerReference.current);
|
|
26
|
+
timerReference.current = null;
|
|
27
|
+
}
|
|
28
|
+
};
|
|
20
29
|
}
|
|
21
30
|
return () => {
|
|
22
31
|
if (timerReference.current) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { memo, useEffect, useState } from "react";
|
|
4
|
+
import { useMounted } from "../../lib/use-mounted";
|
|
4
5
|
import { Badge } from "../badge";
|
|
5
6
|
import {
|
|
6
7
|
Card,
|
|
@@ -29,11 +30,13 @@ function TutorialCardImpl({
|
|
|
29
30
|
tutorial
|
|
30
31
|
}) {
|
|
31
32
|
const [progress, setProgress] = useState(null);
|
|
32
|
-
const
|
|
33
|
+
const isHydrated = useMounted();
|
|
33
34
|
useEffect(() => {
|
|
34
|
-
setIsHydrated(true);
|
|
35
35
|
if (getProgress) {
|
|
36
|
-
|
|
36
|
+
const result = getProgress(tutorial.id);
|
|
37
|
+
requestAnimationFrame(() => {
|
|
38
|
+
setProgress(result);
|
|
39
|
+
});
|
|
37
40
|
}
|
|
38
41
|
}, [getProgress, tutorial.id]);
|
|
39
42
|
const difficultyVariant = DIFFICULTY_VARIANTS[tutorial.difficulty];
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { memo, Suspense } from "react";
|
|
4
|
+
import { usePathname, useRouter, useSearchParams } from "next/navigation";
|
|
5
|
+
import { cn } from "../../lib/utils";
|
|
6
|
+
function ViewSwitcherInner({
|
|
7
|
+
className,
|
|
8
|
+
defaultKey,
|
|
9
|
+
options,
|
|
10
|
+
paramName: parameterName = "view"
|
|
11
|
+
}) {
|
|
12
|
+
const router = useRouter();
|
|
13
|
+
const pathname = usePathname();
|
|
14
|
+
const searchParameters = useSearchParams();
|
|
15
|
+
const resolvedDefault = defaultKey ?? options[0]?.key ?? "";
|
|
16
|
+
const currentKey = searchParameters.get(parameterName) ?? resolvedDefault;
|
|
17
|
+
function handleSelect(key) {
|
|
18
|
+
const parameters = new URLSearchParams(searchParameters.toString());
|
|
19
|
+
if (key === resolvedDefault) {
|
|
20
|
+
parameters.delete(parameterName);
|
|
21
|
+
} else {
|
|
22
|
+
parameters.set(parameterName, key);
|
|
23
|
+
}
|
|
24
|
+
const query = parameters.toString();
|
|
25
|
+
router.push(query ? `${pathname}?${query}` : pathname, { scroll: false });
|
|
26
|
+
}
|
|
27
|
+
return /* @__PURE__ */ jsx(
|
|
28
|
+
"div",
|
|
29
|
+
{
|
|
30
|
+
className: cn(
|
|
31
|
+
"inline-flex items-center rounded-lg border bg-muted p-1",
|
|
32
|
+
className
|
|
33
|
+
),
|
|
34
|
+
role: "tablist",
|
|
35
|
+
children: options.map((option) => /* @__PURE__ */ jsx(
|
|
36
|
+
"button",
|
|
37
|
+
{
|
|
38
|
+
"aria-selected": currentKey === option.key,
|
|
39
|
+
className: cn(
|
|
40
|
+
"rounded-md px-3 py-1.5 text-sm font-medium transition-colors",
|
|
41
|
+
currentKey === option.key ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"
|
|
42
|
+
),
|
|
43
|
+
onClick: () => {
|
|
44
|
+
handleSelect(option.key);
|
|
45
|
+
},
|
|
46
|
+
role: "tab",
|
|
47
|
+
type: "button",
|
|
48
|
+
children: option.label
|
|
49
|
+
},
|
|
50
|
+
option.key
|
|
51
|
+
))
|
|
52
|
+
}
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
function ViewSwitcherFallback({
|
|
56
|
+
className,
|
|
57
|
+
defaultKey,
|
|
58
|
+
options
|
|
59
|
+
}) {
|
|
60
|
+
const resolvedDefault = defaultKey ?? options[0]?.key ?? "";
|
|
61
|
+
return /* @__PURE__ */ jsx(
|
|
62
|
+
"div",
|
|
63
|
+
{
|
|
64
|
+
className: cn(
|
|
65
|
+
"inline-flex items-center rounded-lg border bg-muted p-1",
|
|
66
|
+
className
|
|
67
|
+
),
|
|
68
|
+
role: "tablist",
|
|
69
|
+
children: options.map((option) => /* @__PURE__ */ jsx(
|
|
70
|
+
"button",
|
|
71
|
+
{
|
|
72
|
+
"aria-selected": resolvedDefault === option.key,
|
|
73
|
+
className: cn(
|
|
74
|
+
"rounded-md px-3 py-1.5 text-sm font-medium transition-colors",
|
|
75
|
+
resolvedDefault === option.key ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"
|
|
76
|
+
),
|
|
77
|
+
role: "tab",
|
|
78
|
+
type: "button",
|
|
79
|
+
children: option.label
|
|
80
|
+
},
|
|
81
|
+
option.key
|
|
82
|
+
))
|
|
83
|
+
}
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
const ViewSwitcher = memo(function ViewSwitcher2(props) {
|
|
87
|
+
return /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx(ViewSwitcherFallback, { ...props }), children: /* @__PURE__ */ jsx(ViewSwitcherInner, { ...props }) });
|
|
88
|
+
});
|
|
89
|
+
ViewSwitcher.displayName = "ViewSwitcher";
|
|
90
|
+
export {
|
|
91
|
+
ViewSwitcher
|
|
92
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -899,7 +899,7 @@ type ComparisonProps = {
|
|
|
899
899
|
before: ComparisonSide;
|
|
900
900
|
title?: string;
|
|
901
901
|
};
|
|
902
|
-
declare function Comparison({ after, before, title }: ComparisonProps): react_jsx_runtime.JSX.Element;
|
|
902
|
+
declare function Comparison({ after, before, title, ...rest }: ComparisonProps & Record<string, unknown>): react_jsx_runtime.JSX.Element | null;
|
|
903
903
|
type BeforeAfterProps = {
|
|
904
904
|
after: ReactNode;
|
|
905
905
|
before: ReactNode;
|
|
@@ -1519,6 +1519,26 @@ declare function useSocialFab(options?: UseSocialFabOptions): {
|
|
|
1519
1519
|
};
|
|
1520
1520
|
};
|
|
1521
1521
|
|
|
1522
|
+
type HorizontalScrollRowProps = {
|
|
1523
|
+
children: ReactNode;
|
|
1524
|
+
className?: string;
|
|
1525
|
+
description?: string;
|
|
1526
|
+
title: string;
|
|
1527
|
+
};
|
|
1528
|
+
declare const HorizontalScrollRow: react.NamedExoticComponent<HorizontalScrollRowProps>;
|
|
1529
|
+
|
|
1530
|
+
type ViewOption = {
|
|
1531
|
+
key: string;
|
|
1532
|
+
label: string;
|
|
1533
|
+
};
|
|
1534
|
+
type ViewSwitcherProps = {
|
|
1535
|
+
className?: string;
|
|
1536
|
+
defaultKey?: string;
|
|
1537
|
+
options: ViewOption[];
|
|
1538
|
+
paramName?: string;
|
|
1539
|
+
};
|
|
1540
|
+
declare const ViewSwitcher: react.NamedExoticComponent<ViewSwitcherProps>;
|
|
1541
|
+
|
|
1522
1542
|
type FlowDiagramNode = {
|
|
1523
1543
|
data: {
|
|
1524
1544
|
description?: string;
|
|
@@ -1832,6 +1852,28 @@ type Content<TSection extends ContentSectionMinimal = ContentSection> = ContentM
|
|
|
1832
1852
|
*/
|
|
1833
1853
|
declare function useDebounce<T>(value: T, delay?: number): T;
|
|
1834
1854
|
|
|
1855
|
+
type UseHorizontalScrollReturn = {
|
|
1856
|
+
canScrollLeft: boolean;
|
|
1857
|
+
canScrollRight: boolean;
|
|
1858
|
+
containerRef: React.RefCallback<HTMLElement>;
|
|
1859
|
+
scroll: (direction: "left" | "right") => void;
|
|
1860
|
+
};
|
|
1861
|
+
/**
|
|
1862
|
+
* Hook for horizontal scroll containers with navigation state.
|
|
1863
|
+
*
|
|
1864
|
+
* @returns Scroll state, ref callback for the container, and scroll function.
|
|
1865
|
+
*
|
|
1866
|
+
* @example
|
|
1867
|
+
* ```tsx
|
|
1868
|
+
* const { canScrollLeft, canScrollRight, containerRef, scroll } = useHorizontalScroll();
|
|
1869
|
+
*
|
|
1870
|
+
* <div ref={containerRef} className="overflow-x-auto">
|
|
1871
|
+
* {children}
|
|
1872
|
+
* </div>
|
|
1873
|
+
* ```
|
|
1874
|
+
*/
|
|
1875
|
+
declare function useHorizontalScroll(): UseHorizontalScrollReturn;
|
|
1876
|
+
|
|
1835
1877
|
declare function cn(...inputs: ClassValue[]): string;
|
|
1836
1878
|
|
|
1837
|
-
export { Accordion, AccordionContent, type AccordionContentProps, AccordionItem, type AccordionItemProps, type AccordionProps, AccordionTrigger, type AccordionTriggerProps, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, AreaChart, AspectRatio, Avatar, AvatarFallback, AvatarImage, Badge, type BadgeProps, BarChart, BeforeAfter, type BeforeAfterProps, BlogCard, Breadcrumb, type BreadcrumbItem, Button, type ButtonProps, Calendar, type CalendarProps, Callout, type CalloutProps, type CalloutVariant, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Carousel, type CarouselApi, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious, CategoryFilter, Checkbox, Checklist, type ChecklistItem, type ChecklistProps, CodeBlock, CodePlayground, type CodePlaygroundProps, Collapsible, CollapsibleContent, CollapsibleTrigger, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, CommonMistake, type CommonMistakeProps, Comparison, type ComparisonProps, CompletionDialog, type CompletionDialogProps, Content, ContentCard, ContentIntro, type ContentIntroLabels, type ContentIntroProps, type ContentIntroSection, type ContentMeta, type ContentProgress, type ContentSection, type ContentSectionMinimal, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, CookieConsent, type CookieConsentProps, type CopyStatus, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, type DifficultyLevel, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Exercise, type ExerciseProps, FAQ, FAQItem, type FAQItemProps, type FAQProps, FileTree, type FileTreeProps, FilterBar, type FilterBarLabels, type FilterBarProps, type FilterOption, type FilterUpdates, FloatingActionButton, type FloatingActionButtonProps, FlowControls, type FlowControlsProps, FlowDiagram, type FlowDiagramEdge, type FlowDiagramNode, type FlowDiagramProps, FlowErrorBoundary, FlowFullscreen, type FlowFullscreenProps, Glossary, type GlossaryProps, HoverCard, HoverCardContent, HoverCardTrigger, InlineInput, type InlineInputProps, Input, InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, KeyConcept, type KeyConceptProps, type KeyboardShortcut, KeyboardShortcutsHelp, type KeyboardShortcutsHelpProps, LANGUAGE_NAMES, Label, LangProvider, LearningObjectives, type LearningObjectivesProps, LineChart, MDXContent, Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarPortal, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger, type ModelInfo, ModelSelector, type ModelSelectorProps, type NavItem, NavbarSaas, type NavbarSaasProps, NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport, Pagination, type PaginationProps, type PlatformConfig, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, Prerequisites, type PrerequisitesProps, ProTip, type ProTipProps, type ProTipVariant, ProfileSection, ProgressBar, type ProgressBarProps, Quiz, type QuizOption, type QuizProps, RadioGroup, RadioGroupItem, ResizableHandle, ResizablePanel, ResizablePanelGroup, ScrollArea, ScrollBar, SearchBar, SearchDialog, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, ShareDialog, type ShareDialogLabels, type SharePlatform as ShareDialogPlatform, type ShareDialogProps, type SharePlatform$1 as SharePlatform, type SharePlatformConfig, ShareSection, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, Sidebar, type SidebarItem, SidebarProvider, type SidebarSection, SidebarToggle, type SidebarToggleProps, SimpleTerminal, type SimpleTerminalProps, Skeleton, Slider, Slideshow, type SlideshowLabels, type SlideshowProps, type SlideshowSection, SocialFAB, type SocialFabActionConfig, type SocialFabLabels, type SocialFabProps, Spinner, type SpinnerProps, Step, StepByStep, type StepByStepProps, StepNavigation, type StepNavigationProps, type StepProps, Summary, type SummaryProps, Switch, TLDRSection, type TOCSection, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableOfContents, TableOfContentsPanel, type TableOfContentsPanelProps, TableRow, Tabs, TabsContent, type TabsContentProps, TabsList, type TabsListProps, type TabsProps, TabsTrigger, type TabsTriggerProps, Terminal, type TerminalLine, type TerminalProps, Textarea, type TextareaProps, ThemeProvider, ThemeToggle, ThinkingBlock, type ThinkingBlockProps, Toast, ToastAction, ToastClose, ToastDescription, type ToastProps, ToastTitle, Toaster, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, TruncatedText, type TruncatedTextProps, TutorialCard, type TutorialCardLabels, type TutorialCardMeta, type TutorialCardProgress, type TutorialCardProps, TutorialComplete, type TutorialCompleteLabels, type TutorialCompleteProps, type TutorialCompleteRelatedContent, type TutorialCompleteSection, TutorialFilters, type TutorialFiltersLabels, type TutorialFiltersProps, TutorialIntroContent, type TutorialIntroContentProps, TutorialMDX, type TutorialMDXProps, type SupportedLanguage as UISupportedLanguage, type UseFlowDiagramOptions, type UseFlowDiagramReturn, VideoEmbed, type VideoEmbedProps, alertVariants, badgeVariants, buttonVariants, cn, cookieConsentVariants, getOtherLanguage, mdxComponents, navigationMenuTriggerStyle, toggleVariants, useDebounce, useFlowDiagram, useMobile, useSidebar, useSocialFab };
|
|
1879
|
+
export { Accordion, AccordionContent, type AccordionContentProps, AccordionItem, type AccordionItemProps, type AccordionProps, AccordionTrigger, type AccordionTriggerProps, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, AreaChart, AspectRatio, Avatar, AvatarFallback, AvatarImage, Badge, type BadgeProps, BarChart, BeforeAfter, type BeforeAfterProps, BlogCard, Breadcrumb, type BreadcrumbItem, Button, type ButtonProps, Calendar, type CalendarProps, Callout, type CalloutProps, type CalloutVariant, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Carousel, type CarouselApi, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious, CategoryFilter, Checkbox, Checklist, type ChecklistItem, type ChecklistProps, CodeBlock, CodePlayground, type CodePlaygroundProps, Collapsible, CollapsibleContent, CollapsibleTrigger, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, CommonMistake, type CommonMistakeProps, Comparison, type ComparisonProps, CompletionDialog, type CompletionDialogProps, Content, ContentCard, ContentIntro, type ContentIntroLabels, type ContentIntroProps, type ContentIntroSection, type ContentMeta, type ContentProgress, type ContentSection, type ContentSectionMinimal, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, CookieConsent, type CookieConsentProps, type CopyStatus, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, type DifficultyLevel, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Exercise, type ExerciseProps, FAQ, FAQItem, type FAQItemProps, type FAQProps, FileTree, type FileTreeProps, FilterBar, type FilterBarLabels, type FilterBarProps, type FilterOption, type FilterUpdates, FloatingActionButton, type FloatingActionButtonProps, FlowControls, type FlowControlsProps, FlowDiagram, type FlowDiagramEdge, type FlowDiagramNode, type FlowDiagramProps, FlowErrorBoundary, FlowFullscreen, type FlowFullscreenProps, Glossary, type GlossaryProps, HorizontalScrollRow, type HorizontalScrollRowProps, HoverCard, HoverCardContent, HoverCardTrigger, InlineInput, type InlineInputProps, Input, InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, KeyConcept, type KeyConceptProps, type KeyboardShortcut, KeyboardShortcutsHelp, type KeyboardShortcutsHelpProps, LANGUAGE_NAMES, Label, LangProvider, LearningObjectives, type LearningObjectivesProps, LineChart, MDXContent, Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarPortal, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger, type ModelInfo, ModelSelector, type ModelSelectorProps, type NavItem, NavbarSaas, type NavbarSaasProps, NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport, Pagination, type PaginationProps, type PlatformConfig, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, Prerequisites, type PrerequisitesProps, ProTip, type ProTipProps, type ProTipVariant, ProfileSection, ProgressBar, type ProgressBarProps, Quiz, type QuizOption, type QuizProps, RadioGroup, RadioGroupItem, ResizableHandle, ResizablePanel, ResizablePanelGroup, ScrollArea, ScrollBar, SearchBar, SearchDialog, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, ShareDialog, type ShareDialogLabels, type SharePlatform as ShareDialogPlatform, type ShareDialogProps, type SharePlatform$1 as SharePlatform, type SharePlatformConfig, ShareSection, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, Sidebar, type SidebarItem, SidebarProvider, type SidebarSection, SidebarToggle, type SidebarToggleProps, SimpleTerminal, type SimpleTerminalProps, Skeleton, Slider, Slideshow, type SlideshowLabels, type SlideshowProps, type SlideshowSection, SocialFAB, type SocialFabActionConfig, type SocialFabLabels, type SocialFabProps, Spinner, type SpinnerProps, Step, StepByStep, type StepByStepProps, StepNavigation, type StepNavigationProps, type StepProps, Summary, type SummaryProps, Switch, TLDRSection, type TOCSection, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableOfContents, TableOfContentsPanel, type TableOfContentsPanelProps, TableRow, Tabs, TabsContent, type TabsContentProps, TabsList, type TabsListProps, type TabsProps, TabsTrigger, type TabsTriggerProps, Terminal, type TerminalLine, type TerminalProps, Textarea, type TextareaProps, ThemeProvider, ThemeToggle, ThinkingBlock, type ThinkingBlockProps, Toast, ToastAction, ToastClose, ToastDescription, type ToastProps, ToastTitle, Toaster, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, TruncatedText, type TruncatedTextProps, TutorialCard, type TutorialCardLabels, type TutorialCardMeta, type TutorialCardProgress, type TutorialCardProps, TutorialComplete, type TutorialCompleteLabels, type TutorialCompleteProps, type TutorialCompleteRelatedContent, type TutorialCompleteSection, TutorialFilters, type TutorialFiltersLabels, type TutorialFiltersProps, TutorialIntroContent, type TutorialIntroContentProps, TutorialMDX, type TutorialMDXProps, type SupportedLanguage as UISupportedLanguage, type UseFlowDiagramOptions, type UseFlowDiagramReturn, VideoEmbed, type VideoEmbedProps, type ViewOption, ViewSwitcher, type ViewSwitcherProps, alertVariants, badgeVariants, buttonVariants, cn, cookieConsentVariants, getOtherLanguage, mdxComponents, navigationMenuTriggerStyle, toggleVariants, useDebounce, useFlowDiagram, useHorizontalScroll, useMobile, useSidebar, useSocialFab };
|
package/dist/index.js
CHANGED
|
@@ -4,10 +4,12 @@ import {
|
|
|
4
4
|
LANGUAGE_NAMES
|
|
5
5
|
} from "./lib/types";
|
|
6
6
|
import { useDebounce } from "./lib/use-debounce";
|
|
7
|
+
import { useHorizontalScroll } from "./lib/use-horizontal-scroll";
|
|
7
8
|
import { cn } from "./lib/utils";
|
|
8
9
|
export {
|
|
9
10
|
LANGUAGE_NAMES,
|
|
10
11
|
cn,
|
|
11
12
|
getOtherLanguage,
|
|
12
|
-
useDebounce
|
|
13
|
+
useDebounce,
|
|
14
|
+
useHorizontalScroll
|
|
13
15
|
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
3
|
+
function useHorizontalScroll() {
|
|
4
|
+
const scrollRef = useRef(void 0);
|
|
5
|
+
const observerRef = useRef(void 0);
|
|
6
|
+
const [canScrollLeft, setCanScrollLeft] = useState(false);
|
|
7
|
+
const [canScrollRight, setCanScrollRight] = useState(false);
|
|
8
|
+
const updateScrollState = useCallback(() => {
|
|
9
|
+
const element = scrollRef.current;
|
|
10
|
+
if (!element) return;
|
|
11
|
+
setCanScrollLeft(element.scrollLeft > 0);
|
|
12
|
+
setCanScrollRight(
|
|
13
|
+
element.scrollLeft + element.clientWidth < element.scrollWidth - 1
|
|
14
|
+
);
|
|
15
|
+
}, []);
|
|
16
|
+
const containerRef = useCallback(
|
|
17
|
+
(node) => {
|
|
18
|
+
if (scrollRef.current) {
|
|
19
|
+
scrollRef.current.removeEventListener("scroll", updateScrollState);
|
|
20
|
+
}
|
|
21
|
+
if (observerRef.current) {
|
|
22
|
+
observerRef.current.disconnect();
|
|
23
|
+
observerRef.current = void 0;
|
|
24
|
+
}
|
|
25
|
+
scrollRef.current = node ?? void 0;
|
|
26
|
+
if (node) {
|
|
27
|
+
node.addEventListener("scroll", updateScrollState, { passive: true });
|
|
28
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
29
|
+
observerRef.current = new ResizeObserver(updateScrollState);
|
|
30
|
+
observerRef.current.observe(node);
|
|
31
|
+
}
|
|
32
|
+
updateScrollState();
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
[updateScrollState]
|
|
36
|
+
);
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
return () => {
|
|
39
|
+
if (scrollRef.current) {
|
|
40
|
+
scrollRef.current.removeEventListener("scroll", updateScrollState);
|
|
41
|
+
}
|
|
42
|
+
if (observerRef.current) {
|
|
43
|
+
observerRef.current.disconnect();
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
}, [updateScrollState]);
|
|
47
|
+
const scroll = useCallback((direction) => {
|
|
48
|
+
const element = scrollRef.current;
|
|
49
|
+
if (!element) return;
|
|
50
|
+
const amount = element.clientWidth * 0.8;
|
|
51
|
+
element.scrollBy({
|
|
52
|
+
behavior: "smooth",
|
|
53
|
+
left: direction === "left" ? -amount : amount
|
|
54
|
+
});
|
|
55
|
+
}, []);
|
|
56
|
+
return { canScrollLeft, canScrollRight, containerRef, scroll };
|
|
57
|
+
}
|
|
58
|
+
export {
|
|
59
|
+
useHorizontalScroll
|
|
60
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useSyncExternalStore } from "react";
|
|
3
|
+
function noop() {
|
|
4
|
+
}
|
|
5
|
+
function subscribe() {
|
|
6
|
+
return noop;
|
|
7
|
+
}
|
|
8
|
+
function useMounted() {
|
|
9
|
+
return useSyncExternalStore(
|
|
10
|
+
subscribe,
|
|
11
|
+
() => true,
|
|
12
|
+
() => false
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
export {
|
|
16
|
+
useMounted
|
|
17
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vllnt/ui",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7-canary.2c4792f",
|
|
4
4
|
"description": "React component library — 93 components built on Radix UI, Tailwind CSS, and CVA",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "vllnt",
|
|
@@ -23,21 +23,40 @@
|
|
|
23
23
|
"shadcn"
|
|
24
24
|
],
|
|
25
25
|
"type": "module",
|
|
26
|
-
"main": "./
|
|
27
|
-
"module": "./
|
|
28
|
-
"types": "./
|
|
26
|
+
"main": "./src/index.ts",
|
|
27
|
+
"module": "./src/index.ts",
|
|
28
|
+
"types": "./src/index.ts",
|
|
29
29
|
"exports": {
|
|
30
30
|
".": {
|
|
31
|
-
"types": "./
|
|
32
|
-
"import": "./
|
|
31
|
+
"types": "./src/index.ts",
|
|
32
|
+
"import": "./src/index.ts"
|
|
33
33
|
},
|
|
34
34
|
"./tailwind-preset": {
|
|
35
|
-
"types": "./
|
|
36
|
-
"import": "./
|
|
35
|
+
"types": "./src/tailwind-preset.ts",
|
|
36
|
+
"import": "./src/tailwind-preset.ts"
|
|
37
37
|
},
|
|
38
38
|
"./styles.css": "./styles.css",
|
|
39
39
|
"./themes/default.css": "./themes/default.css"
|
|
40
40
|
},
|
|
41
|
+
"publishConfig": {
|
|
42
|
+
"registry": "https://registry.npmjs.org",
|
|
43
|
+
"access": "public",
|
|
44
|
+
"main": "./dist/index.js",
|
|
45
|
+
"module": "./dist/index.js",
|
|
46
|
+
"types": "./dist/index.d.ts",
|
|
47
|
+
"exports": {
|
|
48
|
+
".": {
|
|
49
|
+
"types": "./dist/index.d.ts",
|
|
50
|
+
"import": "./dist/index.js"
|
|
51
|
+
},
|
|
52
|
+
"./tailwind-preset": {
|
|
53
|
+
"types": "./dist/tailwind-preset.d.ts",
|
|
54
|
+
"import": "./dist/tailwind-preset.js"
|
|
55
|
+
},
|
|
56
|
+
"./styles.css": "./styles.css",
|
|
57
|
+
"./themes/default.css": "./themes/default.css"
|
|
58
|
+
}
|
|
59
|
+
},
|
|
41
60
|
"files": [
|
|
42
61
|
"dist",
|
|
43
62
|
"styles.css",
|
|
@@ -46,6 +65,20 @@
|
|
|
46
65
|
"sideEffects": [
|
|
47
66
|
"*.css"
|
|
48
67
|
],
|
|
68
|
+
"scripts": {
|
|
69
|
+
"build": "tsup",
|
|
70
|
+
"clean": "rm -rf dist node_modules coverage .snapshots playwright-report test-results",
|
|
71
|
+
"lint": "eslint .",
|
|
72
|
+
"lint:fix": "eslint . --fix",
|
|
73
|
+
"check:circular": "madge --circular --extensions ts,tsx src",
|
|
74
|
+
"test": "vitest",
|
|
75
|
+
"test:once": "vitest run",
|
|
76
|
+
"test:coverage": "vitest run --coverage",
|
|
77
|
+
"test:visual": "playwright test -c playwright-ct.config.ts",
|
|
78
|
+
"test:visual:update": "playwright test -c playwright-ct.config.ts --update-snapshots",
|
|
79
|
+
"test:all": "pnpm test:coverage && pnpm test:visual",
|
|
80
|
+
"test:generate": "tsx scripts/generate-tests.ts"
|
|
81
|
+
},
|
|
49
82
|
"peerDependencies": {
|
|
50
83
|
"react": ">=18.0.0",
|
|
51
84
|
"react-dom": ">=18.0.0",
|
|
@@ -125,19 +158,5 @@
|
|
|
125
158
|
"tsx": "^4.21.0",
|
|
126
159
|
"typescript": "^5.9.3",
|
|
127
160
|
"vitest": "^4.0.16"
|
|
128
|
-
},
|
|
129
|
-
"scripts": {
|
|
130
|
-
"build": "tsup",
|
|
131
|
-
"clean": "rm -rf dist node_modules coverage .snapshots playwright-report test-results",
|
|
132
|
-
"lint": "eslint .",
|
|
133
|
-
"lint:fix": "eslint . --fix",
|
|
134
|
-
"check:circular": "madge --circular --extensions ts,tsx src",
|
|
135
|
-
"test": "vitest",
|
|
136
|
-
"test:once": "vitest run",
|
|
137
|
-
"test:coverage": "vitest run --coverage",
|
|
138
|
-
"test:visual": "playwright test -c playwright-ct.config.ts",
|
|
139
|
-
"test:visual:update": "playwright test -c playwright-ct.config.ts --update-snapshots",
|
|
140
|
-
"test:all": "pnpm test:coverage && pnpm test:visual",
|
|
141
|
-
"test:generate": "tsx scripts/generate-tests.ts"
|
|
142
161
|
}
|
|
143
|
-
}
|
|
162
|
+
}
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2025 vllnt
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|