@vllnt/ui 0.3.0 → 0.4.0-canary.4c6891e

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.
@@ -0,0 +1,22 @@
1
+ import { createElement } from "react";
2
+ import { cn } from "../../lib/utils";
3
+ const displayBase = "font-[family-name:var(--font-display)] [font-weight:var(--font-weight-display)] text-[length:var(--font-size-display)] leading-[var(--line-height-display)] text-balance tracking-tight text-foreground";
4
+ const Display = ({
5
+ animated = false,
6
+ as = "div",
7
+ className,
8
+ ref,
9
+ ...props
10
+ }) => createElement(as, {
11
+ className: cn(
12
+ displayBase,
13
+ animated && "motion-safe:animate-[vllnt-animated-text-reveal_0.6s_ease-out_both]",
14
+ className
15
+ ),
16
+ ref,
17
+ ...props
18
+ });
19
+ Display.displayName = "Display";
20
+ export {
21
+ Display
22
+ };
@@ -0,0 +1,4 @@
1
+ import { Display } from "./display";
2
+ export {
3
+ Display
4
+ };
@@ -0,0 +1,40 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { cn } from "../../lib/utils";
3
+ const headingTag = {
4
+ 1: "h1",
5
+ 2: "h2",
6
+ 3: "h3",
7
+ 4: "h4",
8
+ 5: "h5",
9
+ 6: "h6"
10
+ };
11
+ const headingSize = {
12
+ 1: "text-[length:var(--font-size-h1)] leading-[var(--line-height-h1)]",
13
+ 2: "text-[length:var(--font-size-h2)] leading-[var(--line-height-h2)]",
14
+ 3: "text-[length:var(--font-size-h3)] leading-[var(--line-height-h3)]",
15
+ 4: "text-[length:var(--font-size-h4)] leading-[var(--line-height-h4)]",
16
+ 5: "text-[length:var(--font-size-h5)] leading-[var(--line-height-h5)]",
17
+ 6: "text-[length:var(--font-size-h6)] leading-[var(--line-height-h6)]"
18
+ };
19
+ const headingBase = "font-[family-name:var(--font-display)] [font-weight:var(--font-weight-heading)] text-balance tracking-tight text-foreground";
20
+ const Heading = ({
21
+ className,
22
+ level = 2,
23
+ ref,
24
+ size,
25
+ ...props
26
+ }) => {
27
+ const Tag = headingTag[level];
28
+ return /* @__PURE__ */ jsx(
29
+ Tag,
30
+ {
31
+ className: cn(headingBase, headingSize[size ?? level], className),
32
+ ref,
33
+ ...props
34
+ }
35
+ );
36
+ };
37
+ Heading.displayName = "Heading";
38
+ export {
39
+ Heading
40
+ };
@@ -0,0 +1,4 @@
1
+ import { Heading } from "./heading";
2
+ export {
3
+ Heading
4
+ };
@@ -999,6 +999,10 @@ import {
999
999
  PanelHeader,
1000
1000
  PanelTitle
1001
1001
  } from "./panel";
1002
+ import { Heading } from "./heading";
1003
+ import { Text, textVariants } from "./text";
1004
+ import { Display } from "./display";
1005
+ import { Prose } from "./prose";
1002
1006
  export {
1003
1007
  AIArtifact,
1004
1008
  AIArtifactContent,
@@ -1186,6 +1190,7 @@ export {
1186
1190
  DialogPortal,
1187
1191
  DialogTitle,
1188
1192
  DialogTrigger,
1193
+ Display,
1189
1194
  Dock,
1190
1195
  DockIcon,
1191
1196
  DocumentSiblingNav,
@@ -1273,6 +1278,7 @@ export {
1273
1278
  H3,
1274
1279
  H4,
1275
1280
  HandoffBeacon,
1281
+ Heading,
1276
1282
  HeatMapOverlay,
1277
1283
  HeatOverlay,
1278
1284
  Highlight,
@@ -1441,6 +1447,7 @@ export {
1441
1447
  PromptInput,
1442
1448
  PromptTemplates,
1443
1449
  PropertySection,
1450
+ Prose,
1444
1451
  QrCode,
1445
1452
  Quiz,
1446
1453
  RadarChart,
@@ -1549,6 +1556,7 @@ export {
1549
1556
  TagGroupItem,
1550
1557
  TagsInput,
1551
1558
  Terminal,
1559
+ Text,
1552
1560
  TextAnimate,
1553
1561
  TextField,
1554
1562
  TextReveal,
@@ -1637,6 +1645,7 @@ export {
1637
1645
  severityBadgeVariants,
1638
1646
  statCardVariants,
1639
1647
  statusIndicatorVariants,
1648
+ textVariants,
1640
1649
  timelineVariants,
1641
1650
  toast,
1642
1651
  toggleVariants,
@@ -0,0 +1,4 @@
1
+ import { Prose } from "./prose";
2
+ export {
3
+ Prose
4
+ };
@@ -0,0 +1,21 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { cn } from "../../lib/utils";
3
+ const proseStyles = cn(
4
+ "font-[family-name:var(--font-sans)] text-[length:var(--font-size-body)] leading-[var(--line-height-body)] text-foreground",
5
+ "[&>*+*]:mt-4",
6
+ "[&_h1]:mt-8 [&_h1]:font-[family-name:var(--font-display)] [&_h1]:[font-weight:var(--font-weight-heading)] [&_h1]:text-[length:var(--font-size-h1)] [&_h1]:leading-[var(--line-height-h1)] [&_h1]:tracking-tight",
7
+ "[&_h2]:mt-8 [&_h2]:font-[family-name:var(--font-display)] [&_h2]:[font-weight:var(--font-weight-heading)] [&_h2]:text-[length:var(--font-size-h2)] [&_h2]:leading-[var(--line-height-h2)] [&_h2]:tracking-tight",
8
+ "[&_h3]:mt-6 [&_h3]:font-[family-name:var(--font-display)] [&_h3]:[font-weight:var(--font-weight-heading)] [&_h3]:text-[length:var(--font-size-h3)] [&_h3]:leading-[var(--line-height-h3)] [&_h3]:tracking-tight",
9
+ "[&_h4]:mt-6 [&_h4]:font-[family-name:var(--font-display)] [&_h4]:[font-weight:var(--font-weight-heading)] [&_h4]:text-[length:var(--font-size-h4)] [&_h4]:leading-[var(--line-height-h4)] [&_h4]:tracking-tight",
10
+ "[&_p]:text-[length:var(--font-size-body)] [&_p]:leading-[var(--line-height-body)]",
11
+ "[&_ul]:my-4 [&_ul]:ml-6 [&_ul]:list-disc [&_ol]:my-4 [&_ol]:ml-6 [&_ol]:list-decimal [&_li]:mt-2",
12
+ "[&_a]:font-medium [&_a]:underline [&_a]:underline-offset-4",
13
+ "[&_blockquote]:mt-6 [&_blockquote]:border-l-2 [&_blockquote]:border-border [&_blockquote]:pl-6 [&_blockquote]:italic",
14
+ "[&_code]:rounded [&_code]:bg-muted [&_code]:px-[0.3rem] [&_code]:py-[0.2rem] [&_code]:font-mono [&_code]:text-[0.9em]",
15
+ "[&_strong]:font-semibold"
16
+ );
17
+ const Prose = ({ className, ref, ...props }) => /* @__PURE__ */ jsx("div", { className: cn(proseStyles, className), ref, ...props });
18
+ Prose.displayName = "Prose";
19
+ export {
20
+ Prose
21
+ };
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
3
  import { useEffect, useRef, useState, useSyncExternalStore } from "react";
4
- import { ChevronDown } from "lucide-react";
4
+ import { ChevronDown, ChevronLeft, ChevronRight } from "lucide-react";
5
5
  import Link from "next/link";
6
6
  import { usePathname } from "next/navigation";
7
7
  import { useMounted } from "../../lib/use-mounted";
@@ -94,6 +94,151 @@ function CollapsibleSection({
94
94
  )
95
95
  ] });
96
96
  }
97
+ const FAMILY_ROW_CLASS = "flex w-full items-center justify-between px-3 py-1.5 rounded-md text-sm text-muted-foreground hover:bg-accent hover:text-accent-foreground transition-colors";
98
+ function FamilyRowLabel({ section }) {
99
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
100
+ /* @__PURE__ */ jsx("span", { children: section.title }),
101
+ /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-xs", children: [
102
+ section.items.length,
103
+ /* @__PURE__ */ jsx(ChevronRight, { className: "size-3" })
104
+ ] })
105
+ ] });
106
+ }
107
+ function FamilyList({
108
+ isMobile,
109
+ onNavigate,
110
+ onOpen,
111
+ sections
112
+ }) {
113
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
114
+ /* @__PURE__ */ jsx("div", { className: "px-3 py-2 text-xs font-semibold text-muted-foreground uppercase tracking-wider", children: "Components" }),
115
+ /* @__PURE__ */ jsx("div", { className: "space-y-0.5", children: sections.map(
116
+ (section) => section.href ? /* @__PURE__ */ jsx(
117
+ Link,
118
+ {
119
+ className: FAMILY_ROW_CLASS,
120
+ href: section.href,
121
+ onClick: () => {
122
+ if (isMobile) {
123
+ onNavigate();
124
+ }
125
+ },
126
+ children: /* @__PURE__ */ jsx(FamilyRowLabel, { section })
127
+ },
128
+ section.title
129
+ ) : /* @__PURE__ */ jsx(
130
+ "button",
131
+ {
132
+ className: FAMILY_ROW_CLASS,
133
+ onClick: () => {
134
+ onOpen(section.title ?? "");
135
+ },
136
+ type: "button",
137
+ children: /* @__PURE__ */ jsx(FamilyRowLabel, { section })
138
+ },
139
+ section.title
140
+ )
141
+ ) })
142
+ ] });
143
+ }
144
+ function FamilyItems({
145
+ isMobile,
146
+ onBack,
147
+ onNavigate,
148
+ pathname,
149
+ section
150
+ }) {
151
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
152
+ /* @__PURE__ */ jsxs(
153
+ "button",
154
+ {
155
+ className: "flex w-full items-center gap-1.5 px-3 py-2 text-xs font-semibold text-muted-foreground uppercase tracking-wider hover:text-foreground transition-colors",
156
+ onClick: onBack,
157
+ type: "button",
158
+ children: [
159
+ /* @__PURE__ */ jsx(ChevronLeft, { className: "size-3" }),
160
+ /* @__PURE__ */ jsx("span", { children: "All families" })
161
+ ]
162
+ }
163
+ ),
164
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-3 pb-1", children: [
165
+ section.href ? /* @__PURE__ */ jsx(
166
+ Link,
167
+ {
168
+ className: "text-sm font-semibold hover:underline",
169
+ href: section.href,
170
+ onClick: () => {
171
+ if (isMobile) {
172
+ onNavigate();
173
+ }
174
+ },
175
+ children: section.title
176
+ }
177
+ ) : /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold", children: section.title }),
178
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: section.items.length })
179
+ ] }),
180
+ /* @__PURE__ */ jsx("div", { className: "space-y-0.5", children: section.items.map((item) => /* @__PURE__ */ jsx(
181
+ Link,
182
+ {
183
+ "aria-current": pathname === item.href ? "page" : void 0,
184
+ className: cn(
185
+ "block px-3 py-1.5 rounded-md text-sm transition-colors",
186
+ pathname === item.href ? "bg-accent text-accent-foreground font-medium" : "text-muted-foreground hover:bg-accent hover:text-accent-foreground"
187
+ ),
188
+ href: item.href,
189
+ onClick: () => {
190
+ if (isMobile) {
191
+ onNavigate();
192
+ }
193
+ },
194
+ children: item.title
195
+ },
196
+ item.href
197
+ )) })
198
+ ] });
199
+ }
200
+ function FamilyNav({
201
+ isMobile,
202
+ onNavigate,
203
+ pathname,
204
+ sections
205
+ }) {
206
+ const activeTitle = sections.find(
207
+ (section) => section.href === pathname || section.items.some((item) => item.href === pathname)
208
+ )?.title ?? null;
209
+ const [routeKey, setRouteKey] = useState(pathname);
210
+ const [openTitle, setOpenTitle] = useState(activeTitle);
211
+ if (routeKey !== pathname) {
212
+ setRouteKey(pathname);
213
+ setOpenTitle(activeTitle);
214
+ }
215
+ const openSection = openTitle === null ? null : sections.find((section) => section.title === openTitle) ?? null;
216
+ if (openSection) {
217
+ return /* @__PURE__ */ jsx(
218
+ FamilyItems,
219
+ {
220
+ isMobile,
221
+ onBack: () => {
222
+ setOpenTitle(null);
223
+ },
224
+ onNavigate,
225
+ pathname,
226
+ section: openSection
227
+ }
228
+ );
229
+ }
230
+ return /* @__PURE__ */ jsx(
231
+ FamilyList,
232
+ {
233
+ isMobile,
234
+ onNavigate,
235
+ onOpen: (title) => {
236
+ setOpenTitle(title);
237
+ },
238
+ sections
239
+ }
240
+ );
241
+ }
97
242
  function Sidebar({ sections }) {
98
243
  const pathname = usePathname();
99
244
  const { open, setOpen } = useSidebar();
@@ -104,6 +249,8 @@ function Sidebar({ sections }) {
104
249
  scrollContainerReference
105
250
  );
106
251
  const collapsed = mounted && !isMobile && !open;
252
+ const familySections = sections.filter((section) => section.family);
253
+ const otherSections = sections.filter((section) => !section.family);
107
254
  return /* @__PURE__ */ jsxs(Fragment, { children: [
108
255
  isMobile && open ? /* @__PURE__ */ jsx(
109
256
  "div",
@@ -145,42 +292,55 @@ function Sidebar({ sections }) {
145
292
  {
146
293
  className: "flex-1 p-4 overflow-y-auto overscroll-contain h-full [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
147
294
  ref: scrollContainerReference,
148
- children: /* @__PURE__ */ jsx("div", { className: "space-y-4", children: sections.map((section, sectionIndex) => {
149
- const sectionItems = /* @__PURE__ */ jsx("div", { className: section.title ? "space-y-0.5" : "space-y-1", children: section.items.map((item) => /* @__PURE__ */ jsx(
150
- Link,
151
- {
152
- className: cn(
153
- section.title ? "block px-3 py-1.5 rounded-md text-sm transition-colors" : "flex items-center px-3 py-2 rounded-md text-sm font-medium transition-colors",
154
- pathname === item.href || item.href === "/" && pathname === "/" ? "bg-accent text-accent-foreground" : section.title ? "text-muted-foreground hover:bg-accent hover:text-accent-foreground" : "hover:bg-accent hover:text-accent-foreground",
155
- section.title && pathname === item.href && "font-medium"
156
- ),
157
- href: item.href,
158
- onClick: () => {
159
- if (isMobile) {
160
- setOpen(false);
161
- }
295
+ children: /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
296
+ otherSections.map((section, sectionIndex) => {
297
+ const sectionItems = /* @__PURE__ */ jsx("div", { className: section.title ? "space-y-0.5" : "space-y-1", children: section.items.map((item) => /* @__PURE__ */ jsx(
298
+ Link,
299
+ {
300
+ className: cn(
301
+ section.title ? "block px-3 py-1.5 rounded-md text-sm transition-colors" : "flex items-center px-3 py-2 rounded-md text-sm font-medium transition-colors",
302
+ pathname === item.href || item.href === "/" && pathname === "/" ? "bg-accent text-accent-foreground" : section.title ? "text-muted-foreground hover:bg-accent hover:text-accent-foreground" : "hover:bg-accent hover:text-accent-foreground",
303
+ section.title && pathname === item.href && "font-medium"
304
+ ),
305
+ href: item.href,
306
+ onClick: () => {
307
+ if (isMobile) {
308
+ setOpen(false);
309
+ }
310
+ },
311
+ children: item.title
162
312
  },
163
- children: item.title
164
- },
165
- item.href
166
- )) });
167
- return /* @__PURE__ */ jsx(
168
- "div",
313
+ item.href
314
+ )) });
315
+ return /* @__PURE__ */ jsx(
316
+ "div",
317
+ {
318
+ className: "space-y-1",
319
+ children: section.title ? /* @__PURE__ */ jsx(
320
+ CollapsibleSection,
321
+ {
322
+ collapsible: section.collapsible,
323
+ defaultOpen: section.defaultOpen ?? true,
324
+ title: section.title,
325
+ children: sectionItems
326
+ }
327
+ ) : sectionItems
328
+ },
329
+ section.title || sectionIndex
330
+ );
331
+ }),
332
+ familySections.length > 0 ? /* @__PURE__ */ jsx(
333
+ FamilyNav,
169
334
  {
170
- className: "space-y-1",
171
- children: section.title ? /* @__PURE__ */ jsx(
172
- CollapsibleSection,
173
- {
174
- collapsible: section.collapsible,
175
- defaultOpen: section.defaultOpen ?? true,
176
- title: section.title,
177
- children: sectionItems
178
- }
179
- ) : sectionItems
180
- },
181
- section.title || sectionIndex
182
- );
183
- }) })
335
+ isMobile,
336
+ onNavigate: () => {
337
+ setOpen(false);
338
+ },
339
+ pathname,
340
+ sections: familySections
341
+ }
342
+ ) : null
343
+ ] })
184
344
  }
185
345
  )
186
346
  ] })
@@ -0,0 +1,5 @@
1
+ import { Text, textVariants } from "./text";
2
+ export {
3
+ Text,
4
+ textVariants
5
+ };
@@ -0,0 +1,48 @@
1
+ import { createElement } from "react";
2
+ import { cva } from "class-variance-authority";
3
+ import { cn } from "../../lib/utils";
4
+ const textVariants = cva(
5
+ "font-[family-name:var(--font-sans)] text-foreground",
6
+ {
7
+ defaultVariants: {
8
+ size: "base",
9
+ tone: "default",
10
+ weight: "normal"
11
+ },
12
+ variants: {
13
+ size: {
14
+ base: "text-[length:var(--font-size-body)] leading-[var(--line-height-body)]",
15
+ caption: "text-[length:var(--font-size-caption)] leading-[var(--line-height-caption)]",
16
+ lead: "text-[length:var(--font-size-body-lg)] leading-[var(--line-height-body-lg)]",
17
+ small: "text-[length:var(--font-size-body-sm)] leading-[var(--line-height-body-sm)]"
18
+ },
19
+ tone: {
20
+ default: "",
21
+ muted: "text-muted-foreground"
22
+ },
23
+ weight: {
24
+ medium: "font-medium",
25
+ normal: "font-normal",
26
+ semibold: "font-semibold"
27
+ }
28
+ }
29
+ }
30
+ );
31
+ const Text = ({
32
+ as = "p",
33
+ className,
34
+ ref,
35
+ size,
36
+ tone,
37
+ weight,
38
+ ...props
39
+ }) => createElement(as, {
40
+ className: cn(textVariants({ size, tone, weight }), className),
41
+ ref,
42
+ ...props
43
+ });
44
+ Text.displayName = "Text";
45
+ export {
46
+ Text,
47
+ textVariants
48
+ };