@vllnt/ui 0.3.0-canary.f713c3c → 0.4.0-canary.56bbaf0

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/CHANGELOG.md CHANGED
@@ -6,7 +6,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
- > Target version: **`0.3.0`** — shipping as `0.3.0-canary.<sha>` on the npm `canary` tag on every merge to main. The stable `latest` release is gated on the [ROADMAP.md](../../ROADMAP.md) shipping criteria and is not yet published.
9
+ _Nothing yet._
10
+
11
+ ## [0.3.0] - 2026-06-26
10
12
 
11
13
  ### Added
12
14
 
@@ -28,7 +30,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
28
30
  - **Inspector + dock panels** — `PropertySection`, `ObjectInspector`, `RelationshipInspector`, `RuntimeOverviewPanel`, `RoutingAssignmentPanel`, `PolicyDeliveryPanel`.
29
31
  - **Runtime overlays** — `AlertPulse`, `ThresholdRing`, `StickyMetric`, `HeatOverlay`, `StateBadgeOverlay`, `MetricCluster`, `JarvisDock`, `ContextLens`.
30
32
  - **Time navigation** — `TimelineScrubber`, `PlaybackGhost`, `BottomActivityStrip`, `RunTimeline`.
31
- - Total component count: **225** (up from 140).
33
+ - **Form primitives (18)** `ButtonGroup`, `InputGroup`, `Field`, `Fieldset`, `Item`, `ColorPicker`, `CheckboxGroup`, `NativeSelect`, `ListBox`, `SearchField`, `TextField`, `PhoneInput`, `TimePicker`, `TimeField`, `DateField`, `DateRangePicker`, `RangeCalendar`, `TagGroup`.
34
+ - **Charts / dataviz (5)** — `PieChart`, `RadarChart`, `GaugeChart`, `SankeyChart`, `ContributionGraph` (joining the existing `BarChart` / `LineChart` / `AreaChart`).
35
+ - **AI primitives (3)** — `Reasoning`, `ChainOfThought`, `PromptInput`.
36
+ - **Core primitives (7)** — `Typography`, `Link`, `Toolbar`, `Meter`, `QrCode`, `Grid`, `Panel`.
37
+ - **Motion / effects (37)** — `BentoGrid`, `Sparkles`, `Typewriter`, `AnimatedList`, `Dock`, `MagneticButton`, `TextShimmer`, `AnimatedBeam`, `AnimatedTabs`, `ScrollProgress`, `ShimmerButton`, `ShimmerText`, `AnimatedGridPattern`, `AnimatedTestimonials`, `AnimatedTooltip`, `BlurReveal`, `CardFlip`, `Cursor`, `DotPattern`, `ExpandableCards`, `FloatingNavbar`, `GlassCard`, `GlassProgress`, `LiquidGlass`, `Magnetic`, `Meteors`, `Particles`, `ProgressiveBlur`, `RevealText`, `ScrambleText`, `ShineBorder`, `ShinyButton`, `SpinningText`, `SpotlightCard`, `TextAnimate`, `TextReveal`, `TiltCard`.
38
+ - Total component count: **309** (up from 140).
32
39
 
33
40
  - **OKLCH theming system** — color tokens migrated to the OKLCH color space, with 13 runtime theme presets (`default`, `matrix`, `dracula`, `synthwave`, `tron`, `cyberpunk`, `nord`, `claude`, `chatgpt`, `gemini`, `dusk`, `cyberlime`, `aura`). New public theme exports from `@vllnt/ui`: `THEME_PRESETS`, `DEFAULT_THEME_PRESET`, `CUSTOM_THEME_NAME`, `isThemePresetName`, the `ThemePreset` and `ThemePresetName` types, plus the `useThemePreset` hook (with `UseThemePresetResult`), `setThemePreset`, and `setCustomTheme` for runtime preset switching and user-supplied custom themes.
34
41
 
@@ -36,12 +43,15 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
36
43
 
37
44
  ### Changed
38
45
 
46
+ - **BREAKING — React 19 required.** The peer dependency moved to `react` / `react-dom` `>=19`; **React 18 is no longer supported**. Components migrated from `React.forwardRef` to the React 19 ref-as-prop pattern, and `useContext` → `use()`. React-18 consumers must upgrade to React 19.
47
+ - **Internal quality sweep** — cleared the react-doctor backlog: `no-react19-deprecated-apis` 456 → 0, plus state/effect warnings (`useEffectEvent` for effect-captured handlers, derived-state, cascading `setState`) and structural warnings (giant-component splits, render-in-render, polymorphic children, passive listeners).
48
+ - **Shared internals** — extracted reusable hooks/utilities (reference-counted body-scroll-lock that fixes a multi-overlay unlock bug, escape-key, live-date, cached `Intl` formatters, clipboard migration) and a Zod parse seam for the registry shape.
39
49
  - Registry installs use a **hybrid CLI strategy** — leaf component source is inlined, sibling registry items resolve via `@vllnt/ui` to keep installs minimal and dedupe shared primitives.
40
50
 
41
- ### Notes
51
+ ### Fixed
42
52
 
43
- - `ROADMAP.md` added at repo root tracking 50 open issues across 8 phases gating the `0.3.0` cut.
44
- - `0.3.0` requires the codebase-health gate (`react-doctor` CI + 0 errors), the agent-first surface (`/llms.txt`, `/mcp`, sitemap, JSON-LD), and the rebuilt landing page before shipping.
53
+ - **Docs sidebar dropped components** the registry category union omitted four categories (`ai`, `billing`, `data-display`, `educational`), silently hiding ~32 components from the docs sidebar; all now render, with a structural fallback so a missing category can no longer regress.
54
+ - **Theme-adaptive chart colors** `CandlestickChart` and `SparklineGrid` series colors now follow the active theme and dark mode instead of hardcoded values.
45
55
 
46
56
  ## [0.2.1] - 2026-04-21
47
57
 
@@ -145,6 +155,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
145
155
 
146
156
  - Initial public publish to the public npm registry.
147
157
 
158
+ [0.3.0]: https://github.com/vllnt/ui/releases/tag/v0.3.0
148
159
  [0.2.1]: https://github.com/vllnt/ui/releases/tag/v0.2.1
149
160
  [0.2.0]: https://github.com/vllnt/ui/releases/tag/v0.2.0
150
161
  [0.1.11]: https://github.com/vllnt/ui/releases/tag/v0.1.11
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @vllnt/ui
2
2
 
3
- React component library — 144 components built on Radix UI primitives, Tailwind CSS, and CVA.
3
+ React component library — 309 components built on Radix UI primitives, Tailwind CSS, and CVA.
4
4
 
5
5
  See [CHANGELOG.md](./CHANGELOG.md) for release history.
6
6
 
@@ -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,116 @@ function CollapsibleSection({
94
94
  )
95
95
  ] });
96
96
  }
97
+ function FamilyList({
98
+ onOpen,
99
+ sections
100
+ }) {
101
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
102
+ /* @__PURE__ */ jsx("div", { className: "px-3 py-2 text-xs font-semibold text-muted-foreground uppercase tracking-wider", children: "Components" }),
103
+ /* @__PURE__ */ jsx("div", { className: "space-y-0.5", children: sections.map((section) => /* @__PURE__ */ jsxs(
104
+ "button",
105
+ {
106
+ className: "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",
107
+ onClick: () => {
108
+ onOpen(section.title ?? "");
109
+ },
110
+ type: "button",
111
+ children: [
112
+ /* @__PURE__ */ jsx("span", { children: section.title }),
113
+ /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-xs", children: [
114
+ section.items.length,
115
+ /* @__PURE__ */ jsx(ChevronRight, { className: "size-3" })
116
+ ] })
117
+ ]
118
+ },
119
+ section.title
120
+ )) })
121
+ ] });
122
+ }
123
+ function FamilyItems({
124
+ isMobile,
125
+ onBack,
126
+ onNavigate,
127
+ pathname,
128
+ section
129
+ }) {
130
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
131
+ /* @__PURE__ */ jsxs(
132
+ "button",
133
+ {
134
+ 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",
135
+ onClick: onBack,
136
+ type: "button",
137
+ children: [
138
+ /* @__PURE__ */ jsx(ChevronLeft, { className: "size-3" }),
139
+ /* @__PURE__ */ jsx("span", { children: "All families" })
140
+ ]
141
+ }
142
+ ),
143
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-3 pb-1", children: [
144
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold", children: section.title }),
145
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: section.items.length })
146
+ ] }),
147
+ /* @__PURE__ */ jsx("div", { className: "space-y-0.5", children: section.items.map((item) => /* @__PURE__ */ jsx(
148
+ Link,
149
+ {
150
+ "aria-current": pathname === item.href ? "page" : void 0,
151
+ className: cn(
152
+ "block px-3 py-1.5 rounded-md text-sm transition-colors",
153
+ pathname === item.href ? "bg-accent text-accent-foreground font-medium" : "text-muted-foreground hover:bg-accent hover:text-accent-foreground"
154
+ ),
155
+ href: item.href,
156
+ onClick: () => {
157
+ if (isMobile) {
158
+ onNavigate();
159
+ }
160
+ },
161
+ children: item.title
162
+ },
163
+ item.href
164
+ )) })
165
+ ] });
166
+ }
167
+ function FamilyNav({
168
+ isMobile,
169
+ onNavigate,
170
+ pathname,
171
+ sections
172
+ }) {
173
+ const activeTitle = sections.find(
174
+ (section) => section.items.some((item) => item.href === pathname)
175
+ )?.title ?? null;
176
+ const [routeKey, setRouteKey] = useState(pathname);
177
+ const [openTitle, setOpenTitle] = useState(activeTitle);
178
+ if (routeKey !== pathname) {
179
+ setRouteKey(pathname);
180
+ setOpenTitle(activeTitle);
181
+ }
182
+ const openSection = openTitle === null ? null : sections.find((section) => section.title === openTitle) ?? null;
183
+ if (openSection) {
184
+ return /* @__PURE__ */ jsx(
185
+ FamilyItems,
186
+ {
187
+ isMobile,
188
+ onBack: () => {
189
+ setOpenTitle(null);
190
+ },
191
+ onNavigate,
192
+ pathname,
193
+ section: openSection
194
+ }
195
+ );
196
+ }
197
+ return /* @__PURE__ */ jsx(
198
+ FamilyList,
199
+ {
200
+ onOpen: (title) => {
201
+ setOpenTitle(title);
202
+ },
203
+ sections
204
+ }
205
+ );
206
+ }
97
207
  function Sidebar({ sections }) {
98
208
  const pathname = usePathname();
99
209
  const { open, setOpen } = useSidebar();
@@ -104,6 +214,8 @@ function Sidebar({ sections }) {
104
214
  scrollContainerReference
105
215
  );
106
216
  const collapsed = mounted && !isMobile && !open;
217
+ const familySections = sections.filter((section) => section.family);
218
+ const otherSections = sections.filter((section) => !section.family);
107
219
  return /* @__PURE__ */ jsxs(Fragment, { children: [
108
220
  isMobile && open ? /* @__PURE__ */ jsx(
109
221
  "div",
@@ -145,42 +257,55 @@ function Sidebar({ sections }) {
145
257
  {
146
258
  className: "flex-1 p-4 overflow-y-auto overscroll-contain h-full [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
147
259
  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
- }
260
+ children: /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
261
+ otherSections.map((section, sectionIndex) => {
262
+ const sectionItems = /* @__PURE__ */ jsx("div", { className: section.title ? "space-y-0.5" : "space-y-1", children: section.items.map((item) => /* @__PURE__ */ jsx(
263
+ Link,
264
+ {
265
+ className: cn(
266
+ 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",
267
+ 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",
268
+ section.title && pathname === item.href && "font-medium"
269
+ ),
270
+ href: item.href,
271
+ onClick: () => {
272
+ if (isMobile) {
273
+ setOpen(false);
274
+ }
275
+ },
276
+ children: item.title
162
277
  },
163
- children: item.title
164
- },
165
- item.href
166
- )) });
167
- return /* @__PURE__ */ jsx(
168
- "div",
278
+ item.href
279
+ )) });
280
+ return /* @__PURE__ */ jsx(
281
+ "div",
282
+ {
283
+ className: "space-y-1",
284
+ children: section.title ? /* @__PURE__ */ jsx(
285
+ CollapsibleSection,
286
+ {
287
+ collapsible: section.collapsible,
288
+ defaultOpen: section.defaultOpen ?? true,
289
+ title: section.title,
290
+ children: sectionItems
291
+ }
292
+ ) : sectionItems
293
+ },
294
+ section.title || sectionIndex
295
+ );
296
+ }),
297
+ familySections.length > 0 ? /* @__PURE__ */ jsx(
298
+ FamilyNav,
169
299
  {
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
- }) })
300
+ isMobile,
301
+ onNavigate: () => {
302
+ setOpen(false);
303
+ },
304
+ pathname,
305
+ sections: familySections
306
+ }
307
+ ) : null
308
+ ] })
184
309
  }
185
310
  )
186
311
  ] })
package/dist/index.d.ts CHANGED
@@ -5049,6 +5049,7 @@ type SidebarItem = {
5049
5049
  type SidebarSection = {
5050
5050
  collapsible?: boolean;
5051
5051
  defaultOpen?: boolean;
5052
+ family?: boolean;
5052
5053
  items: SidebarItem[];
5053
5054
  title?: string;
5054
5055
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@vllnt/ui",
3
- "version": "0.3.0-canary.f713c3c",
4
- "description": "React component library — 225 components built on Radix UI, Tailwind CSS, and CVA",
3
+ "version": "0.4.0-canary.56bbaf0",
4
+ "description": "React component library — 309 components built on Radix UI, Tailwind CSS, and CVA",
5
5
  "license": "MIT",
6
6
  "author": "vllnt",
7
7
  "homepage": "https://ui.vllnt.ai",