drivn 1.12.0 → 1.13.0

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.
Files changed (3) hide show
  1. package/README.md +45 -0
  2. package/dist/index.js +443 -30
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -92,6 +92,51 @@ export function ConfirmDialog() {
92
92
  }
93
93
  ```
94
94
 
95
+ ## MCP Server
96
+
97
+ Connect your AI assistant directly to the Drivn component registry via the [Model Context Protocol](https://modelcontextprotocol.io). Instead of copy-pasting component code into chat, your AI gets exact source code, design tokens, and coding conventions automatically.
98
+
99
+ ### Claude Code
100
+
101
+ ```sh
102
+ claude mcp add drivn -- npx drivn@latest mcp
103
+ ```
104
+
105
+ ### Cursor
106
+
107
+ ```sh
108
+ npx @anthropic-ai/cursor-mcp-installer drivn -- npx drivn@latest mcp
109
+ ```
110
+
111
+ ### Manual configuration
112
+
113
+ For any MCP-compatible client, add the following to your config file:
114
+
115
+ ```json
116
+ {
117
+ "mcpServers": {
118
+ "drivn": {
119
+ "command": "npx",
120
+ "args": ["drivn@latest", "mcp"]
121
+ }
122
+ }
123
+ }
124
+ ```
125
+
126
+ ### Available tools
127
+
128
+ | Tool | Description |
129
+ |---|---|
130
+ | `list_components` | List all available components with descriptions |
131
+ | `get_component` | Get full source code and metadata for a component |
132
+ | `get_component_metadata` | Get metadata only (no source) — useful for planning |
133
+ | `search_components` | Search components by name or description |
134
+ | `get_installation_instructions` | Get step-by-step install instructions with dependency resolution |
135
+ | `get_design_tokens` | Get CSS design tokens (globals and theme tokens) |
136
+ | `get_drivn_rules` | Get Drivn coding conventions and component patterns |
137
+
138
+ ---
139
+
95
140
  ## License
96
141
 
97
142
  Licensed under the [MIT License](./LICENSE.md).
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import {Command}from'commander';import*as n from'@clack/prompts';import u from'picocolors';import {join,dirname}from'path';import {execSync}from'child_process';import {existsSync,readFileSync,writeFileSync,mkdirSync}from'fs';import {McpServer}from'@modelcontextprotocol/sdk/server/mcp.js';import {StdioServerTransport}from'@modelcontextprotocol/sdk/server/stdio.js';import {z as z$1}from'zod';var z={next:"Next.js",react:"React"};function V(e){let r=join(e,"package.json");if(!existsSync(r))throw new Error("package.json not found");let t=JSON.parse(readFileSync(r,"utf-8")),a={...t.dependencies,...t.devDependencies},l="react";a.next&&(l="next");let d=existsSync(join(e,"src")),p=existsSync(join(e,"tsconfig.json"));return {framework:l,srcDir:d,typescript:p}}var F="drivn.config.json";function U(e){let r=join(e,F);return existsSync(r)?JSON.parse(readFileSync(r,"utf-8")):null}function K(e,r){let t=join(e,F);writeFileSync(t,JSON.stringify(r,null,2));}function Ve(e){existsSync(e)||mkdirSync(e,{recursive:true});}function b(e,r){Ve(dirname(e)),writeFileSync(e,r);}function H(e){return readFileSync(e,"utf-8")}function x(e){return existsSync(e)}function E(e){return existsSync(join(e,"pnpm-lock.yaml"))?"pnpm":"npm"}function w(e,r){let t=r.join(" ");return e==="pnpm"?`pnpm add ${t}`:`npm install ${t}`}function W(e){return e==="pnpm"?"pnpm dlx":"npx"}var C=`@import "tailwindcss";
2
+ import {Command}from'commander';import*as n from'@clack/prompts';import u from'picocolors';import {join,dirname}from'path';import {execSync}from'child_process';import {existsSync,readFileSync,writeFileSync,mkdirSync}from'fs';import {McpServer}from'@modelcontextprotocol/sdk/server/mcp.js';import {StdioServerTransport}from'@modelcontextprotocol/sdk/server/stdio.js';import {z as z$1}from'zod';var j={next:"Next.js",react:"React"};function V(e){let r=join(e,"package.json");if(!existsSync(r))throw new Error("package.json not found");let t=JSON.parse(readFileSync(r,"utf-8")),a={...t.dependencies,...t.devDependencies},l="react";a.next&&(l="next");let d=existsSync(join(e,"src")),p=existsSync(join(e,"tsconfig.json"));return {framework:l,srcDir:d,typescript:p}}var F="drivn.config.json";function U(e){let r=join(e,F);return existsSync(r)?JSON.parse(readFileSync(r,"utf-8")):null}function K(e,r){let t=join(e,F);writeFileSync(t,JSON.stringify(r,null,2));}function _e(e){existsSync(e)||mkdirSync(e,{recursive:true});}function b(e,r){_e(dirname(e)),writeFileSync(e,r);}function H(e){return readFileSync(e,"utf-8")}function x(e){return existsSync(e)}function E(e){return existsSync(join(e,"pnpm-lock.yaml"))?"pnpm":"npm"}function w(e,r){let t=r.join(" ");return e==="pnpm"?`pnpm add ${t}`:`npm install ${t}`}function Y(e){return e==="pnpm"?"pnpm dlx":"npx"}var C=`@import "tailwindcss";
3
3
 
4
4
  :root {
5
5
  /* Surfaces */
@@ -136,13 +136,13 @@ body {
136
136
  /* Special Surfaces */
137
137
  --overlay: hsl(0 0% 0% / 0.18);
138
138
  }
139
- `;var Fe=`import { type ClassValue, clsx } from 'clsx'
139
+ `;var Ke=`import { type ClassValue, clsx } from 'clsx'
140
140
  import { twMerge } from 'tailwind-merge'
141
141
 
142
142
  export function cn(...inputs: ClassValue[]) {
143
143
  return twMerge(clsx(inputs))
144
144
  }
145
- `,Ue=["src/app/globals.css","src/styles/globals.css","src/styles/globals.scss","app/globals.css"];function Ke(e){for(let r of Ue)if(x(join(e,r)))return r;return null}async function Y(){let e=process.cwd();console.log(""),console.log(u.bgCyan(u.bold(u.black(" Drivn "))));let r;try{r=V(e),n.log.success(`Detected ${u.cyan(z[r.framework])}`);}catch{n.log.error("No package.json found. Run this command in a project directory."),n.outro("Setup cancelled"),process.exit(1);}if(x(join(e,"drivn.config.json"))){let s=await n.confirm({message:"Config already exists. Overwrite?",initialValue:false});(n.isCancel(s)||!s)&&(n.cancel("Setup cancelled"),process.exit(0));}let t=r.srcDir?"src/components/ui":"components/ui",a=r.srcDir?"src/utils":"utils",l=await n.group({components:()=>n.text({message:"Where should components be installed?",placeholder:t,defaultValue:t}),utils:()=>n.text({message:"Where should utilities be placed?",placeholder:a,defaultValue:a})},{onCancel:()=>{n.cancel("Setup cancelled"),process.exit(0);}}),d={framework:r.framework,typescript:r.typescript,paths:{components:l.components,utils:l.utils},installed:[]},p=r.typescript?"ts":"js",f=join(e,l.utils,`cn.${p}`);x(f)||b(f,Fe);let g=Ke(e);if(g){let s=await n.confirm({message:`Found ${u.cyan(g)}. Add Drivn color tokens?`,initialValue:true});!n.isCancel(s)&&s&&(b(join(e,g),C),d.paths.globals=g,n.log.success(`Color tokens written to ${u.cyan(g)}`));}else {let s=r.srcDir?"src/styles/globals.css":"styles/globals.css",i=await n.text({message:"Where should the globals CSS file be created?",placeholder:s,defaultValue:s});n.isCancel(i)||(b(join(e,i),C),d.paths.globals=i,n.log.success(`Color tokens written to ${u.cyan(i)}`));}K(e,d);let N=E(e),m=W(N),h=["clsx","tailwind-merge","lucide-react"],o=n.spinner();o.start("Installing dependencies");try{execSync(w(N,h),{cwd:e,stdio:"ignore"}),o.stop("Dependencies installed");}catch{o.stop("Failed to install dependencies"),n.log.warn(`Run manually: ${w(N,h)}`);}n.log.info(`Add components with: ${u.cyan(`${m} drivn add button`)}`),n.log.info(`Add dark/light theme: ${u.cyan(`${m} drivn add theme`)}`),n.outro("Drivn initialized");}var X=`'use client'
145
+ `,Ye=["src/app/globals.css","src/styles/globals.css","src/styles/globals.scss","app/globals.css"];function We(e){for(let r of Ye)if(x(join(e,r)))return r;return null}async function W(){let e=process.cwd();console.log(""),console.log(u.bgCyan(u.bold(u.black(" Drivn "))));let r;try{r=V(e),n.log.success(`Detected ${u.cyan(j[r.framework])}`);}catch{n.log.error("No package.json found. Run this command in a project directory."),n.outro("Setup cancelled"),process.exit(1);}if(x(join(e,"drivn.config.json"))){let s=await n.confirm({message:"Config already exists. Overwrite?",initialValue:false});(n.isCancel(s)||!s)&&(n.cancel("Setup cancelled"),process.exit(0));}let t=r.srcDir?"src/components/ui":"components/ui",a=r.srcDir?"src/utils":"utils",l=await n.group({components:()=>n.text({message:"Where should components be installed?",placeholder:t,defaultValue:t}),utils:()=>n.text({message:"Where should utilities be placed?",placeholder:a,defaultValue:a})},{onCancel:()=>{n.cancel("Setup cancelled"),process.exit(0);}}),d={framework:r.framework,typescript:r.typescript,paths:{components:l.components,utils:l.utils},installed:[]},p=r.typescript?"ts":"js",f=join(e,l.utils,`cn.${p}`);x(f)||b(f,Ke);let g=We(e);if(g){let s=await n.confirm({message:`Found ${u.cyan(g)}. Add Drivn color tokens?`,initialValue:true});!n.isCancel(s)&&s&&(b(join(e,g),C),d.paths.globals=g,n.log.success(`Color tokens written to ${u.cyan(g)}`));}else {let s=r.srcDir?"src/styles/globals.css":"styles/globals.css",i=await n.text({message:"Where should the globals CSS file be created?",placeholder:s,defaultValue:s});n.isCancel(i)||(b(join(e,i),C),d.paths.globals=i,n.log.success(`Color tokens written to ${u.cyan(i)}`));}K(e,d);let N=E(e),m=Y(N),h=["clsx","tailwind-merge","lucide-react"],o=n.spinner();o.start("Installing dependencies");try{execSync(w(N,h),{cwd:e,stdio:"ignore"}),o.stop("Dependencies installed");}catch{o.stop("Failed to install dependencies"),n.log.warn(`Run manually: ${w(N,h)}`);}n.log.info(`Add components with: ${u.cyan(`${m} drivn add button`)}`),n.log.info(`Add dark/light theme: ${u.cyan(`${m} drivn add theme`)}`),n.outro("Drivn initialized");}var X=`'use client'
146
146
 
147
147
  import { ThemeProvider as NextThemesProvider } from 'next-themes'
148
148
 
@@ -2155,6 +2155,283 @@ export const Collapsible = Object.assign(CollapsibleRoot, {
2155
2155
  })
2156
2156
  `;var pe=`'use client'
2157
2157
 
2158
+ import * as React from 'react'
2159
+ import { ChevronRight } from 'lucide-react'
2160
+ import { cn } from '@/utils/cn'
2161
+
2162
+ const styles = {
2163
+ trigger: 'contents',
2164
+ content: cn(
2165
+ 'fixed min-w-[180px] z-50',
2166
+ 'bg-card border border-border rounded-[10px] p-1',
2167
+ 'shadow-lg',
2168
+ 'transition-[opacity,visibility] duration-150 ease-in'
2169
+ ),
2170
+ item: cn(
2171
+ 'flex items-center gap-2 w-full px-3 py-2',
2172
+ 'text-sm text-foreground rounded-lg',
2173
+ 'hover:bg-accent transition-colors cursor-pointer'
2174
+ ),
2175
+ destructive: 'text-destructive hover:bg-destructive/10',
2176
+ disabled: 'opacity-50 pointer-events-none',
2177
+ shortcut: 'ml-auto text-xs text-muted-foreground',
2178
+ group: 'py-1',
2179
+ label: cn(
2180
+ 'px-3 py-1.5 text-xs font-medium',
2181
+ 'text-muted-foreground'
2182
+ ),
2183
+ separator: 'my-1 h-px bg-border',
2184
+ sub: 'relative group/sub',
2185
+ subContent: cn(
2186
+ 'absolute left-full top-0 min-w-[180px] z-50',
2187
+ 'bg-card border border-border rounded-[10px] p-1',
2188
+ 'shadow-lg',
2189
+ 'transition-[opacity,visibility] duration-150 ease-in',
2190
+ 'opacity-0 invisible',
2191
+ 'group-hover/sub:opacity-100',
2192
+ 'group-hover/sub:visible',
2193
+ 'group-hover/sub:ease-out'
2194
+ ),
2195
+ }
2196
+
2197
+ interface ContextMenuCtx {
2198
+ open: boolean
2199
+ setOpen: (v: boolean) => void
2200
+ pos: { x: number; y: number }
2201
+ }
2202
+
2203
+ type IconProp = React.ComponentType<{ className?: string }> | React.ReactElement
2204
+
2205
+ function ContextMenuRoot({
2206
+ children,
2207
+ className,
2208
+ }: {
2209
+ children: React.ReactNode
2210
+ className?: string
2211
+ }) {
2212
+ const [open, setOpen] = React.useState(false)
2213
+ const [pos, setPos] = React.useState({ x: 0, y: 0 })
2214
+
2215
+ React.useEffect(() => {
2216
+ if (!open) return
2217
+ const close = () => setOpen(false)
2218
+ const onKeyDown = (e: KeyboardEvent) => {
2219
+ if (e.key === 'Escape') close()
2220
+ }
2221
+ document.addEventListener('mousedown', close)
2222
+ document.addEventListener('keydown', onKeyDown)
2223
+ return () => {
2224
+ document.removeEventListener('mousedown', close)
2225
+ document.removeEventListener('keydown', onKeyDown)
2226
+ }
2227
+ }, [open])
2228
+
2229
+ const onContextMenu = React.useCallback(
2230
+ (e: React.MouseEvent) => {
2231
+ e.preventDefault()
2232
+ setPos({ x: e.clientX, y: e.clientY })
2233
+ setOpen(true)
2234
+ }, [])
2235
+
2236
+ return (
2237
+ <Ctx.Provider value={{ open, setOpen, pos }}>
2238
+ <div className={className}>
2239
+ <div className={styles.trigger} onContextMenu={onContextMenu}>
2240
+ {children}
2241
+ </div>
2242
+ </div>
2243
+ </Ctx.Provider>
2244
+ )
2245
+ }
2246
+
2247
+ function Trigger({
2248
+ children,
2249
+ }: {
2250
+ children: React.ReactNode
2251
+ }) {
2252
+ return <>{children}</>
2253
+ }
2254
+
2255
+ function Content({
2256
+ children,
2257
+ className,
2258
+ }: {
2259
+ children: React.ReactNode
2260
+ className?: string
2261
+ }) {
2262
+ const { open, pos } = useContextMenu()
2263
+ return (
2264
+ <div
2265
+ style={{ left: pos.x, top: pos.y }}
2266
+ className={cn(
2267
+ styles.content,
2268
+ open ? 'opacity-100 visible ease-out' : 'opacity-0 invisible',
2269
+ className
2270
+ )}
2271
+ >
2272
+ {children}
2273
+ </div>
2274
+ )
2275
+ }
2276
+
2277
+ function Item({
2278
+ children,
2279
+ onClick,
2280
+ icon: Icon,
2281
+ shortcut,
2282
+ destructive,
2283
+ disabled,
2284
+ className,
2285
+ ...props
2286
+ }: {
2287
+ children: React.ReactNode
2288
+ onClick?: () => void
2289
+ icon?: IconProp
2290
+ shortcut?: string
2291
+ destructive?: boolean
2292
+ disabled?: boolean
2293
+ className?: string
2294
+ } & Omit<
2295
+ React.ButtonHTMLAttributes<HTMLButtonElement>,
2296
+ 'onClick' | 'disabled'
2297
+ >) {
2298
+ const { setOpen } = useContextMenu()
2299
+ return (
2300
+ <button
2301
+ disabled={disabled}
2302
+ className={cn(
2303
+ styles.item,
2304
+ destructive && styles.destructive,
2305
+ disabled && styles.disabled,
2306
+ className
2307
+ )}
2308
+ onClick={() => {
2309
+ onClick?.()
2310
+ setOpen(false)
2311
+ }}
2312
+ {...props}
2313
+ >
2314
+ {Icon && (React.isValidElement(Icon) ? Icon : <Icon className="w-4 h-4" />)}
2315
+ {children}
2316
+ {shortcut && (
2317
+ <span className={styles.shortcut}>{shortcut}</span>
2318
+ )}
2319
+ </button>
2320
+ )
2321
+ }
2322
+
2323
+ function Sub({
2324
+ children,
2325
+ className,
2326
+ }: {
2327
+ children: React.ReactNode
2328
+ className?: string
2329
+ }) {
2330
+ return (
2331
+ <div className={cn(styles.sub, className)}>
2332
+ {children}
2333
+ </div>
2334
+ )
2335
+ }
2336
+
2337
+ function SubTrigger({
2338
+ children,
2339
+ icon: Icon,
2340
+ className,
2341
+ ...props
2342
+ }: {
2343
+ children: React.ReactNode
2344
+ icon?: IconProp
2345
+ className?: string
2346
+ } & Omit<
2347
+ React.ButtonHTMLAttributes<HTMLButtonElement>,
2348
+ 'children'
2349
+ >) {
2350
+ return (
2351
+ <button
2352
+ className={cn(styles.item, className)}
2353
+ {...props}
2354
+ >
2355
+ {Icon && (React.isValidElement(Icon) ? Icon : <Icon className="w-4 h-4" />)}
2356
+ {children}
2357
+ <ChevronRight className="ml-auto w-4 h-4" />
2358
+ </button>
2359
+ )
2360
+ }
2361
+
2362
+ function SubContent({
2363
+ children,
2364
+ className,
2365
+ }: {
2366
+ children: React.ReactNode
2367
+ className?: string
2368
+ }) {
2369
+ return (
2370
+ <div className={cn(styles.subContent, className)}>
2371
+ {children}
2372
+ </div>
2373
+ )
2374
+ }
2375
+
2376
+ function Group({
2377
+ children,
2378
+ className,
2379
+ }: {
2380
+ children: React.ReactNode
2381
+ className?: string
2382
+ }) {
2383
+ return (
2384
+ <div className={cn(styles.group, className)}>
2385
+ {children}
2386
+ </div>
2387
+ )
2388
+ }
2389
+
2390
+ function ContextMenuLabel({
2391
+ children,
2392
+ className,
2393
+ }: {
2394
+ children: React.ReactNode
2395
+ className?: string
2396
+ }) {
2397
+ return (
2398
+ <div className={cn(styles.label, className)}>
2399
+ {children}
2400
+ </div>
2401
+ )
2402
+ }
2403
+
2404
+ function ContextMenuSeparator({
2405
+ className,
2406
+ }: {
2407
+ className?: string
2408
+ }) {
2409
+ return (
2410
+ <div className={cn(styles.separator, className)} />
2411
+ )
2412
+ }
2413
+
2414
+ const Ctx = React.createContext<ContextMenuCtx | null>(null)
2415
+
2416
+ function useContextMenu() {
2417
+ const ctx = React.useContext(Ctx)
2418
+ if (!ctx) throw new Error('ContextMenu compound used outside <ContextMenu>')
2419
+ return ctx
2420
+ }
2421
+
2422
+ export const ContextMenu = Object.assign(ContextMenuRoot, {
2423
+ Trigger,
2424
+ Content,
2425
+ Item,
2426
+ Sub,
2427
+ SubTrigger,
2428
+ SubContent,
2429
+ Group,
2430
+ Label: ContextMenuLabel,
2431
+ Separator: ContextMenuSeparator,
2432
+ })
2433
+ `;var ue=`'use client'
2434
+
2158
2435
  import * as React from 'react'
2159
2436
  import { X } from 'lucide-react'
2160
2437
  import { cn } from '@/utils/cn'
@@ -2309,7 +2586,7 @@ export const Dialog = Object.assign(DialogRoot, {
2309
2586
  Trigger,
2310
2587
  Content,
2311
2588
  })
2312
- `;var ue=`'use client'
2589
+ `;var me=`'use client'
2313
2590
 
2314
2591
  import * as React from 'react'
2315
2592
  import { X } from 'lucide-react'
@@ -2528,7 +2805,7 @@ export const Drawer = Object.assign(DrawerRoot, {
2528
2805
  Header,
2529
2806
  Footer,
2530
2807
  })
2531
- `;var me=`'use client'
2808
+ `;var fe=`'use client'
2532
2809
 
2533
2810
  import * as React from 'react'
2534
2811
  import { cn } from '@/utils/cn'
@@ -2726,7 +3003,7 @@ export const Dropdown = Object.assign(DropdownRoot, {
2726
3003
  Label,
2727
3004
  Separator: DropdownSeparator
2728
3005
  })
2729
- `;var fe=`import * as React from 'react'
3006
+ `;var ge=`import * as React from 'react'
2730
3007
  import { cn } from '@/utils/cn'
2731
3008
 
2732
3009
  const styles = {
@@ -2749,7 +3026,7 @@ export const Input = React.forwardRef<HTMLInputElement, InputProps>(({
2749
3026
  )
2750
3027
 
2751
3028
  Input.displayName = 'Input'
2752
- `;var ge=`import * as React from 'react'
3029
+ `;var he=`import * as React from 'react'
2753
3030
  import { cn } from '@/utils/cn'
2754
3031
 
2755
3032
  const styles = {
@@ -2806,7 +3083,7 @@ function Group({
2806
3083
  }
2807
3084
 
2808
3085
  export const Kbd = Object.assign(KbdRoot, { Group })
2809
- `;var he=`import * as React from 'react'
3086
+ `;var be=`import * as React from 'react'
2810
3087
  import { cn } from '@/utils/cn'
2811
3088
 
2812
3089
  export function Label({
@@ -2823,7 +3100,143 @@ export function Label({
2823
3100
  />
2824
3101
  )
2825
3102
  }
2826
- `;var be=`import * as React from 'react'
3103
+ `;var ve=`'use client'
3104
+
3105
+ import * as React from 'react'
3106
+ import { ChevronDown } from 'lucide-react'
3107
+ import { cn } from '@/utils/cn'
3108
+
3109
+ const styles = {
3110
+ root: 'relative',
3111
+ list: 'flex items-center gap-1',
3112
+ item: 'relative',
3113
+ trigger: cn(
3114
+ 'inline-flex items-center gap-1 px-3 py-2',
3115
+ 'text-sm font-medium text-foreground rounded-lg',
3116
+ 'hover:bg-accent transition-colors cursor-pointer',
3117
+ 'outline-none'
3118
+ ),
3119
+ triggerIcon: 'w-3.5 h-3.5 transition-transform duration-200',
3120
+ content: cn(
3121
+ 'absolute left-0 top-full min-w-[220px] z-50',
3122
+ 'bg-card border border-border rounded-xl p-2',
3123
+ 'shadow-lg shadow-black/8',
3124
+ 'origin-[var(--origin)]',
3125
+ 'transition-[opacity,visibility]',
3126
+ 'duration-150 ease-in'
3127
+ ),
3128
+ link: cn(
3129
+ 'flex w-full gap-3 px-3 py-2.5',
3130
+ 'text-sm font-medium text-foreground rounded-lg',
3131
+ 'hover:bg-accent transition-colors cursor-pointer',
3132
+ 'no-underline outline-none'
3133
+ ),
3134
+ }
3135
+
3136
+ function NavigationMenuRoot({
3137
+ children,
3138
+ className,
3139
+ }: {
3140
+ children: React.ReactNode
3141
+ className?: string
3142
+ }) {
3143
+ return (
3144
+ <nav className={cn(styles.root, className)}>
3145
+ {children}
3146
+ </nav>
3147
+ )
3148
+ }
3149
+
3150
+ function List({
3151
+ children,
3152
+ className,
3153
+ }: {
3154
+ children: React.ReactNode
3155
+ className?: string
3156
+ }) {
3157
+ return (
3158
+ <ul className={cn(styles.list, className)}>
3159
+ {children}
3160
+ </ul>
3161
+ )
3162
+ }
3163
+
3164
+ function Item({
3165
+ children,
3166
+ className,
3167
+ }: {
3168
+ children: React.ReactNode
3169
+ className?: string
3170
+ }) {
3171
+ return (
3172
+ <li className={cn('group/item', styles.item, className)}>
3173
+ {children}
3174
+ </li>
3175
+ )
3176
+ }
3177
+
3178
+ function Trigger({
3179
+ children,
3180
+ className,
3181
+ ...props
3182
+ }: React.ButtonHTMLAttributes<HTMLButtonElement>) {
3183
+ return (
3184
+ <button className={cn(styles.trigger, className)} {...props}>
3185
+ {children}
3186
+ <ChevronDown className={cn(styles.triggerIcon, 'group-hover/item:rotate-180')} />
3187
+ </button>
3188
+ )
3189
+ }
3190
+
3191
+ function Content({
3192
+ children,
3193
+ className,
3194
+ }: {
3195
+ children: React.ReactNode
3196
+ className?: string
3197
+ }) {
3198
+ return (
3199
+ <div
3200
+ style={{ '--origin': '0 0' } as React.CSSProperties}
3201
+ className={cn(
3202
+ styles.content,
3203
+ 'opacity-0 invisible',
3204
+ 'group-hover/item:opacity-100',
3205
+ 'group-hover/item:visible',
3206
+ 'group-hover/item:ease-out',
3207
+ className
3208
+ )}
3209
+ >
3210
+ {children}
3211
+ </div>
3212
+ )
3213
+ }
3214
+
3215
+ function Link({
3216
+ children,
3217
+ href,
3218
+ className,
3219
+ ...props
3220
+ }: React.AnchorHTMLAttributes<HTMLAnchorElement>) {
3221
+ return (
3222
+ <a
3223
+ href={href}
3224
+ className={cn(styles.link, className)}
3225
+ {...props}
3226
+ >
3227
+ {children}
3228
+ </a>
3229
+ )
3230
+ }
3231
+
3232
+ export const NavigationMenu = Object.assign(NavigationMenuRoot, {
3233
+ List,
3234
+ Item,
3235
+ Trigger,
3236
+ Content,
3237
+ Link
3238
+ })
3239
+ `;var xe=`import * as React from 'react'
2827
3240
  import { ChevronLeft, ChevronRight, MoreHorizontal } from 'lucide-react'
2828
3241
  import { cn } from '@/utils/cn'
2829
3242
 
@@ -2956,7 +3369,7 @@ export const Pagination = Object.assign(PaginationRoot, {
2956
3369
  Next,
2957
3370
  Ellipsis: PaginationEllipsis,
2958
3371
  })
2959
- `;var ve=`'use client'
3372
+ `;var ye=`'use client'
2960
3373
 
2961
3374
  import * as React from 'react'
2962
3375
  import { cn } from '@/utils/cn'
@@ -3061,7 +3474,7 @@ export const Popover = Object.assign(PopoverRoot, {
3061
3474
  Trigger,
3062
3475
  Content
3063
3476
  })
3064
- `;var xe=`import * as React from 'react'
3477
+ `;var Ne=`import * as React from 'react'
3065
3478
  import { cn } from '@/utils/cn'
3066
3479
 
3067
3480
  const styles = {
@@ -3099,7 +3512,7 @@ export function Progress({
3099
3512
  </div>
3100
3513
  )
3101
3514
  }
3102
- `;var ye=`'use client'
3515
+ `;var Ce=`'use client'
3103
3516
 
3104
3517
  import * as React from 'react'
3105
3518
  import { cn } from '@/utils/cn'
@@ -3248,7 +3661,7 @@ function useRadioGroup() {
3248
3661
  }
3249
3662
 
3250
3663
  export const RadioGroup = Object.assign(RadioGroupRoot, { Item })
3251
- `;var Ne=`'use client'
3664
+ `;var Re=`'use client'
3252
3665
 
3253
3666
  import * as React from 'react'
3254
3667
  import { ChevronDown } from 'lucide-react'
@@ -3404,7 +3817,7 @@ export const Select = Object.assign(SelectRoot, {
3404
3817
  Menu,
3405
3818
  Option
3406
3819
  })
3407
- `;var Ce=`import * as React from 'react'
3820
+ `;var we=`import * as React from 'react'
3408
3821
  import { cn } from '@/utils/cn'
3409
3822
 
3410
3823
  const styles = {
@@ -3450,7 +3863,7 @@ export function ScrollArea({
3450
3863
  </div>
3451
3864
  )
3452
3865
  }
3453
- `;var Re=`import * as React from 'react'
3866
+ `;var ke=`import * as React from 'react'
3454
3867
  import { cn } from '@/utils/cn'
3455
3868
 
3456
3869
  const styles = {
@@ -3474,7 +3887,7 @@ export function Separator({
3474
3887
  />
3475
3888
  )
3476
3889
  }
3477
- `;var we=`import * as React from 'react'
3890
+ `;var Pe=`import * as React from 'react'
3478
3891
  import { cn } from '@/utils/cn'
3479
3892
 
3480
3893
  export function Skeleton({
@@ -3491,7 +3904,7 @@ export function Skeleton({
3491
3904
  />
3492
3905
  )
3493
3906
  }
3494
- `;var ke=`'use client'
3907
+ `;var Se=`'use client'
3495
3908
 
3496
3909
  import * as React from 'react'
3497
3910
  import { ChevronDown, PanelLeft } from 'lucide-react'
@@ -3777,7 +4190,7 @@ export const Sidebar = Object.assign(SidebarRoot, {
3777
4190
  Separator: SidebarSeparator,
3778
4191
  CollapseButton,
3779
4192
  })
3780
- `;var Pe=`'use client'
4193
+ `;var De=`'use client'
3781
4194
 
3782
4195
  import * as React from 'react'
3783
4196
  import { cn } from '@/utils/cn'
@@ -3922,7 +4335,7 @@ export const Slider = React.forwardRef<HTMLInputElement, SliderProps>(({
3922
4335
  )
3923
4336
 
3924
4337
  Slider.displayName = 'Slider'
3925
- `;var Se=`'use client'
4338
+ `;var Te=`'use client'
3926
4339
 
3927
4340
  import * as React from 'react'
3928
4341
  import { cn } from '@/utils/cn'
@@ -3964,7 +4377,7 @@ export function Switch({
3964
4377
  </button>
3965
4378
  )
3966
4379
  }
3967
- `;var De=`'use client'
4380
+ `;var Ie=`'use client'
3968
4381
 
3969
4382
  import * as React from 'react'
3970
4383
  import { cn } from '@/utils/cn'
@@ -4078,7 +4491,7 @@ export const Tabs = Object.assign(TabsRoot, {
4078
4491
  Tab,
4079
4492
  Panel
4080
4493
  })
4081
- `;var Te=`import * as React from 'react'
4494
+ `;var Ee=`import * as React from 'react'
4082
4495
  import { cn } from '@/utils/cn'
4083
4496
 
4084
4497
  const styles = {
@@ -4105,7 +4518,7 @@ export const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(({
4105
4518
  ))
4106
4519
 
4107
4520
  Textarea.displayName = 'Textarea'
4108
- `;var Ie=`'use client'
4521
+ `;var Le=`'use client'
4109
4522
 
4110
4523
  import * as React from 'react'
4111
4524
  import { Toaster as Sonner, toast } from 'sonner'
@@ -4148,7 +4561,7 @@ function Toaster() {
4148
4561
  }
4149
4562
 
4150
4563
  export { Toaster, toast }
4151
- `;var Ee=`'use client'
4564
+ `;var Me=`'use client'
4152
4565
 
4153
4566
  import * as React from 'react'
4154
4567
  import { cn } from '@/utils/cn'
@@ -4310,7 +4723,7 @@ const Ctx = React.createContext<ToggleGroupCtx | null>(null)
4310
4723
  export const Toggle = Object.assign(ToggleButton, {
4311
4724
  Group: ToggleGroupRoot,
4312
4725
  })
4313
- `;var Le=`import * as React from 'react'
4726
+ `;var Oe=`import * as React from 'react'
4314
4727
  import { cn } from '@/utils/cn'
4315
4728
 
4316
4729
  const styles = {
@@ -4484,7 +4897,7 @@ export const Table = Object.assign(TableRoot, {
4484
4897
  Head,
4485
4898
  Cell,
4486
4899
  })
4487
- `;var Oe=`import * as React from 'react'
4900
+ `;var Ae=`import * as React from 'react'
4488
4901
  import { cn } from '@/utils/cn'
4489
4902
 
4490
4903
  const styles = {
@@ -4529,7 +4942,7 @@ export function Tooltip({
4529
4942
  </span>
4530
4943
  )
4531
4944
  }
4532
- `;var Me=`
4945
+ `;var Be=`
4533
4946
  /* react-day-picker theme integration */
4534
4947
  .rdp-root {
4535
4948
  --rdp-accent-color: var(--primary);
@@ -4540,7 +4953,7 @@ export function Tooltip({
4540
4953
  --rdp-selected-border: none;
4541
4954
  --rdp-day_button-border: none;
4542
4955
  }
4543
- `,v=[{name:"accordion",description:"Collapsible content sections with dot notation and smooth animation",dependencies:[],npmDependencies:[]},{name:"alert",description:"Contextual feedback messages with variants and icons",dependencies:[],npmDependencies:[]},{name:"aspect-ratio",description:"Maintain consistent width-to-height ratios for images, videos, and embedded content",dependencies:[],npmDependencies:[]},{name:"avatar",description:"User avatar with image support and fallback initials",dependencies:[],npmDependencies:[]},{name:"badge",description:"Small status indicator with color variants",dependencies:[],npmDependencies:[]},{name:"breadcrumb",description:"Breadcrumb navigation with auto-separators, ellipsis, and dot notation",dependencies:[],npmDependencies:[]},{name:"button",description:"Button with variants, sizes, loading state, and icon slots",dependencies:[],npmDependencies:[]},{name:"calendar",description:"Date picker powered by react-day-picker with single, range, and dropdown modes",dependencies:[],npmDependencies:["react-day-picker"]},{name:"date-picker",description:"Date picker input with Calendar dropdown for single date and range selection",dependencies:["calendar"],npmDependencies:[]},{name:"command",description:"Searchable command menu with filtering, keyboard navigation, and dialog mode",dependencies:["dialog"],npmDependencies:["cmdk"]},{name:"carousel",description:"Carousel with touch/swipe, navigation arrows, dot indicators, and loop mode",dependencies:["button"],npmDependencies:["embla-carousel-react"]},{name:"card",description:"Container with dot notation preview and info sub-components",dependencies:[],npmDependencies:[]},{name:"checkbox",description:"Checkbox input with label and CSS-only checkmark",dependencies:[],npmDependencies:[]},{name:"combobox",description:"Searchable select with filtering, single/multi selection, and keyboard navigation",dependencies:[],npmDependencies:["cmdk"]},{name:"collapsible",description:"Toggle content visibility with smooth animation and accessible controls",dependencies:[],npmDependencies:[]},{name:"dialog",description:"Modal dialog with dot notation, overlay, and escape key",dependencies:["button"],npmDependencies:[]},{name:"drawer",description:"Slide-in panel with side positioning, header/footer, and overlay",dependencies:["button"],npmDependencies:[]},{name:"dropdown",description:"Dropdown menu with dot notation, groups, separators, and click-outside",dependencies:["button"],npmDependencies:[]},{name:"input",description:"Text input with focus ring and disabled state",dependencies:[],npmDependencies:[]},{name:"kbd",description:"Keyboard key display for shortcuts and hotkeys",dependencies:[],npmDependencies:[]},{name:"label",description:"Accessible form label for inputs, checkboxes, and selects",dependencies:[],npmDependencies:[]},{name:"pagination",description:"Page navigation with dot notation, Previous/Next, ellipsis, and active state",dependencies:[],npmDependencies:[]},{name:"popover",description:"Floating content panel with dot notation and click-outside",dependencies:["button"],npmDependencies:[]},{name:"progress",description:"Progress bar with animated fill and ARIA attributes",dependencies:[],npmDependencies:[]},{name:"radio-group",description:"Radio group with dot notation, orientation support, and controlled/uncontrolled selection",dependencies:[],npmDependencies:[]},{name:"select",description:"Custom select with dot notation and composable options",dependencies:[],npmDependencies:[]},{name:"scroll-area",description:"Themed scrollable container with custom scrollbar styling and orientation control",dependencies:[],npmDependencies:[]},{name:"separator",description:"Visual divider with horizontal and vertical orientation",dependencies:[],npmDependencies:[]},{name:"skeleton",description:"Loading placeholder with pulse animation, sized and shaped via className",dependencies:[],npmDependencies:[]},{name:"sidebar",description:"Collapsible sidebar with dot notation, icon items, groups, and layout variants",dependencies:[],npmDependencies:[]},{name:"slider",description:"Range slider with pointer drag, step snapping, and size variants",dependencies:[],npmDependencies:[]},{name:"switch",description:"Toggle switch with smooth transition",dependencies:[],npmDependencies:[]},{name:"tabs",description:"Tab navigation with dot notation and panel content",dependencies:[],npmDependencies:[]},{name:"table",description:"Data table with dot notation, striped/bordered variants, and responsive overflow",dependencies:[],npmDependencies:[]},{name:"textarea",description:"Multi-line text input with consistent styling",dependencies:[],npmDependencies:[]},{name:"theme",description:"Dark/light theme support with next-themes and ThemeProvider",dependencies:[],npmDependencies:["next-themes"]},{name:"toast",description:"Toast notifications powered by Sonner",dependencies:[],npmDependencies:["sonner"]},{name:"toggle",description:"Toggle button with pressed state, single and multiple selection groups",dependencies:[],npmDependencies:[]},{name:"tooltip",description:"Pure CSS tooltip with 4 position options",dependencies:[],npmDependencies:[]}],R={accordion:q,alert:J,"aspect-ratio":Z,avatar:Q,badge:ee,breadcrumb:te,button:ne,calendar:oe,"date-picker":re,command:se,carousel:ae,card:ie,checkbox:ce,combobox:le,collapsible:de,dialog:pe,drawer:ue,dropdown:me,input:fe,kbd:ge,label:he,pagination:be,popover:ve,progress:xe,"radio-group":ye,select:Ne,"scroll-area":Ce,separator:Re,skeleton:we,sidebar:ke,slider:Pe,switch:Se,table:Le,tabs:De,textarea:Te,theme:X,toast:Ie,toggle:Ee,tooltip:Oe};async function Ae(e){let r=process.cwd();n.intro("drivn add");let t=U(r);if(t||(n.log.error("Drivn is not initialized. Run npx drivn@latest create"),n.outro("Cancelled"),process.exit(1)),!e||!e.length){let o=await n.multiselect({message:"Select components to add",options:v.map(s=>({label:s.name,hint:s.description,value:s.name})),required:true});n.isCancel(o)&&(n.cancel("Cancelled"),process.exit(0)),e=o;}let a=e.filter(o=>!v.find(s=>s.name===o));a.length&&(n.log.error(`Unknown components: ${a.join(", ")}`),n.log.info("Available: "+v.map(o=>o.name).join(", ")),n.outro("Cancelled"),process.exit(1));let l=e.includes("theme"),d=e.filter(o=>o!=="theme"),p=new Set,f=new Set,g=o=>{if(p.has(o))return;let s=v.find(i=>i.name===o);s&&(s.dependencies.forEach(i=>g(i)),s.npmDependencies?.forEach(i=>f.add(i)),p.add(o));};d.forEach(g),l&&f.add("next-themes");let N=[...p].filter(o=>!d.includes(o));N.length&&n.log.info(`Required dependency: ${N.join(", ")}`);let m=t.typescript?"tsx":"jsx",h=join(r,t.paths.components);for(let o of p){let s=join(h,`${o}.${m}`);if(x(s)){let S=await n.confirm({message:`${o}.${m} exists. Overwrite?`,initialValue:false});if(n.isCancel(S)||!S){n.log.warn(`Skipped ${o}`);continue}}let i=R[o];i=i.replace(/@\/utils/g,`@/${t.paths.utils.replace(/^src\//,"")}`),b(s,i),n.log.success(`${o} \u2192 ${t.paths.components}/${o}.${m}`);}if(l){let o=join(h,`theme-provider.${m}`);if(x(o)){let i=await n.confirm({message:`theme-provider.${m} exists. Overwrite?`,initialValue:false});!n.isCancel(i)&&i?(b(o,R.theme),n.log.success(`theme-provider \u2192 ${t.paths.components}/theme-provider.${m}`)):n.log.warn("Skipped theme-provider");}else b(o,R.theme),n.log.success(`theme-provider \u2192 ${t.paths.components}/theme-provider.${m}`);if(t.paths.globals){let i=join(r,t.paths.globals);if(x(i)){let S=H(i);S.includes('[data-theme="dark"]')?n.log.warn("Theme tokens already exist in globals \u2014 skipped"):(b(i,S+k),n.log.success(`Theme tokens appended to ${u.cyan(t.paths.globals)}`));}else n.log.warn(`Globals file not found at ${t.paths.globals}`);}else n.log.warn('No globals path in drivn.config.json. Add "globals" to paths');let s=t.paths.components.replace(/^src\//,"@/");n.log.message(""),n.log.info(u.bold("Complete the setup:")),n.log.message(""),n.log.message(u.bold(`${u.cyan("1.")} Import ThemeProvider in your root layout:`)),n.log.message(u.cyan(` import { ThemeProvider } from "${s}/theme-provider"`)),n.log.message(""),n.log.message(u.bold(`${u.cyan("2.")} Add suppressHydrationWarning to <html>:`)),n.log.message(u.cyan(" <html suppressHydrationWarning>")),n.log.message(""),n.log.message(u.bold(`${u.cyan("3.")} Wrap your app with ThemeProvider:`)),n.log.message(u.cyan(" <ThemeProvider>")),n.log.message(u.cyan(" {children}")),n.log.message(u.cyan(" </ThemeProvider>")),n.log.message("");}if(p.has("calendar")&&t.paths.globals){let o=join(r,t.paths.globals);if(x(o)){let s=H(o);s.includes(".rdp-root")?n.log.warn("Calendar tokens already exist in globals \u2014 skipped"):(b(o,s+Me),n.log.success(`Calendar tokens appended to ${u.cyan(t.paths.globals)}`));}}if(f.size){let o=E(r),s=[...f],i=n.spinner();i.start("Installing packages");try{execSync(w(o,s),{cwd:r,stdio:"ignore"}),i.stop("Packages installed");}catch{i.stop("Failed to install packages"),n.log.warn(`Run manually: ${w(o,s)}`);}}n.outro("Done.");}var j=`# Drivn Component Conventions
4956
+ `,v=[{name:"accordion",description:"Collapsible content sections with dot notation and smooth animation",dependencies:[],npmDependencies:[]},{name:"alert",description:"Contextual feedback messages with variants and icons",dependencies:[],npmDependencies:[]},{name:"aspect-ratio",description:"Maintain consistent width-to-height ratios for images, videos, and embedded content",dependencies:[],npmDependencies:[]},{name:"avatar",description:"User avatar with image support and fallback initials",dependencies:[],npmDependencies:[]},{name:"badge",description:"Small status indicator with color variants",dependencies:[],npmDependencies:[]},{name:"breadcrumb",description:"Breadcrumb navigation with auto-separators, ellipsis, and dot notation",dependencies:[],npmDependencies:[]},{name:"button",description:"Button with variants, sizes, loading state, and icon slots",dependencies:[],npmDependencies:[]},{name:"calendar",description:"Date picker powered by react-day-picker with single, range, and dropdown modes",dependencies:[],npmDependencies:["react-day-picker"]},{name:"date-picker",description:"Date picker input with Calendar dropdown for single date and range selection",dependencies:["calendar"],npmDependencies:[]},{name:"command",description:"Searchable command menu with filtering, keyboard navigation, and dialog mode",dependencies:["dialog"],npmDependencies:["cmdk"]},{name:"carousel",description:"Carousel with touch/swipe, navigation arrows, dot indicators, and loop mode",dependencies:["button"],npmDependencies:["embla-carousel-react"]},{name:"card",description:"Container with dot notation preview and info sub-components",dependencies:[],npmDependencies:[]},{name:"checkbox",description:"Checkbox input with label and CSS-only checkmark",dependencies:[],npmDependencies:[]},{name:"combobox",description:"Searchable select with filtering, single/multi selection, and keyboard navigation",dependencies:[],npmDependencies:["cmdk"]},{name:"collapsible",description:"Toggle content visibility with smooth animation and accessible controls",dependencies:[],npmDependencies:[]},{name:"context-menu",description:"Right-click context menu with submenus, keyboard shortcuts, icons, and dot notation",dependencies:[],npmDependencies:[]},{name:"dialog",description:"Modal dialog with dot notation, overlay, and escape key",dependencies:["button"],npmDependencies:[]},{name:"drawer",description:"Slide-in panel with side positioning, header/footer, and overlay",dependencies:["button"],npmDependencies:[]},{name:"dropdown",description:"Dropdown menu with dot notation, groups, separators, and click-outside",dependencies:["button"],npmDependencies:[]},{name:"input",description:"Text input with focus ring and disabled state",dependencies:[],npmDependencies:[]},{name:"kbd",description:"Keyboard key display for shortcuts and hotkeys",dependencies:[],npmDependencies:[]},{name:"label",description:"Accessible form label for inputs, checkboxes, and selects",dependencies:[],npmDependencies:[]},{name:"navigation-menu",description:"Horizontal navigation menu with dropdown content panels and dot notation",dependencies:[],npmDependencies:[]},{name:"pagination",description:"Page navigation with dot notation, Previous/Next, ellipsis, and active state",dependencies:[],npmDependencies:[]},{name:"popover",description:"Floating content panel with dot notation and click-outside",dependencies:["button"],npmDependencies:[]},{name:"progress",description:"Progress bar with animated fill and ARIA attributes",dependencies:[],npmDependencies:[]},{name:"radio-group",description:"Radio group with dot notation, orientation support, and controlled/uncontrolled selection",dependencies:[],npmDependencies:[]},{name:"select",description:"Custom select with dot notation and composable options",dependencies:[],npmDependencies:[]},{name:"scroll-area",description:"Themed scrollable container with custom scrollbar styling and orientation control",dependencies:[],npmDependencies:[]},{name:"separator",description:"Visual divider with horizontal and vertical orientation",dependencies:[],npmDependencies:[]},{name:"skeleton",description:"Loading placeholder with pulse animation, sized and shaped via className",dependencies:[],npmDependencies:[]},{name:"sidebar",description:"Collapsible sidebar with dot notation, icon items, groups, and layout variants",dependencies:[],npmDependencies:[]},{name:"slider",description:"Range slider with pointer drag, step snapping, and size variants",dependencies:[],npmDependencies:[]},{name:"switch",description:"Toggle switch with smooth transition",dependencies:[],npmDependencies:[]},{name:"tabs",description:"Tab navigation with dot notation and panel content",dependencies:[],npmDependencies:[]},{name:"table",description:"Data table with dot notation, striped/bordered variants, and responsive overflow",dependencies:[],npmDependencies:[]},{name:"textarea",description:"Multi-line text input with consistent styling",dependencies:[],npmDependencies:[]},{name:"theme",description:"Dark/light theme support with next-themes and ThemeProvider",dependencies:[],npmDependencies:["next-themes"]},{name:"toast",description:"Toast notifications powered by Sonner",dependencies:[],npmDependencies:["sonner"]},{name:"toggle",description:"Toggle button with pressed state, single and multiple selection groups",dependencies:[],npmDependencies:[]},{name:"tooltip",description:"Pure CSS tooltip with 4 position options",dependencies:[],npmDependencies:[]}],R={accordion:q,alert:J,"aspect-ratio":Z,avatar:Q,badge:ee,breadcrumb:te,button:ne,calendar:oe,"date-picker":re,command:se,carousel:ae,card:ie,checkbox:ce,combobox:le,collapsible:de,"context-menu":pe,dialog:ue,drawer:me,dropdown:fe,input:ge,kbd:he,label:be,"navigation-menu":ve,pagination:xe,popover:ye,progress:Ne,"radio-group":Ce,select:Re,"scroll-area":we,separator:ke,skeleton:Pe,sidebar:Se,slider:De,switch:Te,table:Oe,tabs:Ie,textarea:Ee,theme:X,toast:Le,toggle:Me,tooltip:Ae};async function He(e){let r=process.cwd();n.intro("drivn add");let t=U(r);if(t||(n.log.error("Drivn is not initialized. Run npx drivn@latest create"),n.outro("Cancelled"),process.exit(1)),!e||!e.length){let o=await n.multiselect({message:"Select components to add",options:v.map(s=>({label:s.name,hint:s.description,value:s.name})),required:true});n.isCancel(o)&&(n.cancel("Cancelled"),process.exit(0)),e=o;}let a=e.filter(o=>!v.find(s=>s.name===o));a.length&&(n.log.error(`Unknown components: ${a.join(", ")}`),n.log.info("Available: "+v.map(o=>o.name).join(", ")),n.outro("Cancelled"),process.exit(1));let l=e.includes("theme"),d=e.filter(o=>o!=="theme"),p=new Set,f=new Set,g=o=>{if(p.has(o))return;let s=v.find(i=>i.name===o);s&&(s.dependencies.forEach(i=>g(i)),s.npmDependencies?.forEach(i=>f.add(i)),p.add(o));};d.forEach(g),l&&f.add("next-themes");let N=[...p].filter(o=>!d.includes(o));N.length&&n.log.info(`Required dependency: ${N.join(", ")}`);let m=t.typescript?"tsx":"jsx",h=join(r,t.paths.components);for(let o of p){let s=join(h,`${o}.${m}`);if(x(s)){let S=await n.confirm({message:`${o}.${m} exists. Overwrite?`,initialValue:false});if(n.isCancel(S)||!S){n.log.warn(`Skipped ${o}`);continue}}let i=R[o];i=i.replace(/@\/utils/g,`@/${t.paths.utils.replace(/^src\//,"")}`),b(s,i),n.log.success(`${o} \u2192 ${t.paths.components}/${o}.${m}`);}if(l){let o=join(h,`theme-provider.${m}`);if(x(o)){let i=await n.confirm({message:`theme-provider.${m} exists. Overwrite?`,initialValue:false});!n.isCancel(i)&&i?(b(o,R.theme),n.log.success(`theme-provider \u2192 ${t.paths.components}/theme-provider.${m}`)):n.log.warn("Skipped theme-provider");}else b(o,R.theme),n.log.success(`theme-provider \u2192 ${t.paths.components}/theme-provider.${m}`);if(t.paths.globals){let i=join(r,t.paths.globals);if(x(i)){let S=H(i);S.includes('[data-theme="dark"]')?n.log.warn("Theme tokens already exist in globals \u2014 skipped"):(b(i,S+k),n.log.success(`Theme tokens appended to ${u.cyan(t.paths.globals)}`));}else n.log.warn(`Globals file not found at ${t.paths.globals}`);}else n.log.warn('No globals path in drivn.config.json. Add "globals" to paths');let s=t.paths.components.replace(/^src\//,"@/");n.log.message(""),n.log.info(u.bold("Complete the setup:")),n.log.message(""),n.log.message(u.bold(`${u.cyan("1.")} Import ThemeProvider in your root layout:`)),n.log.message(u.cyan(` import { ThemeProvider } from "${s}/theme-provider"`)),n.log.message(""),n.log.message(u.bold(`${u.cyan("2.")} Add suppressHydrationWarning to <html>:`)),n.log.message(u.cyan(" <html suppressHydrationWarning>")),n.log.message(""),n.log.message(u.bold(`${u.cyan("3.")} Wrap your app with ThemeProvider:`)),n.log.message(u.cyan(" <ThemeProvider>")),n.log.message(u.cyan(" {children}")),n.log.message(u.cyan(" </ThemeProvider>")),n.log.message("");}if(p.has("calendar")&&t.paths.globals){let o=join(r,t.paths.globals);if(x(o)){let s=H(o);s.includes(".rdp-root")?n.log.warn("Calendar tokens already exist in globals \u2014 skipped"):(b(o,s+Be),n.log.success(`Calendar tokens appended to ${u.cyan(t.paths.globals)}`));}}if(f.size){let o=E(r),s=[...f],i=n.spinner();i.start("Installing packages");try{execSync(w(o,s),{cwd:r,stdio:"ignore"}),i.stop("Packages installed");}catch{i.stop("Failed to install packages"),n.log.warn(`Run manually: ${w(o,s)}`);}}n.outro("Done.");}var z=`# Drivn Component Conventions
4544
4957
 
4545
4958
  ## Core Philosophy
4546
4959
  - **Zero runtime UI deps** \u2014 No Radix, no cva, no external UI primitives. Pure React + Tailwind.
@@ -4653,13 +5066,13 @@ import { cn } from '@/utils/cn'
4653
5066
  - Components declare internal deps (other Drivn components)
4654
5067
  - Some components need npm packages (react-day-picker, cmdk, embla-carousel-react, sonner)
4655
5068
  - The CLI resolves and installs all dependencies automatically
4656
- `;var L={version:"1.12.0"};function O(e){return v.find(r=>r.name===e)}function Je(e){let r=new Set,t=a=>{if(r.has(a))return;let l=O(a);l&&(l.dependencies.forEach(d=>t(d)),r.add(a));};return t(e),r.delete(e),[...r]}async function Be(){let e=new McpServer({name:"drivn",version:L.version});e.tool("list_components","List all available Drivn UI components with descriptions",{},async()=>({content:[{type:"text",text:JSON.stringify(v.map(t=>({name:t.name,description:t.description})),null,2)}]})),e.tool("get_component","Get the full source code and metadata for a Drivn component",{name:z$1.string().describe('Component name (e.g. "button", "dialog")')},async({name:t})=>{let a=O(t);if(!a)return {content:[{type:"text",text:`Component "${t}" not found. Use list_components to see available components.`}],isError:true};let l=R[t];return {content:[{type:"text",text:JSON.stringify({name:a.name,description:a.description,dependencies:a.dependencies,npmDependencies:a.npmDependencies,source:l},null,2)}]}}),e.tool("get_component_metadata","Get metadata only (no source code) for a Drivn component \u2014 useful for planning",{name:z$1.string().describe("Component name")},async({name:t})=>{let a=O(t);if(!a)return {content:[{type:"text",text:`Component "${t}" not found. Use list_components to see available components.`}],isError:true};let l=Je(t);return {content:[{type:"text",text:JSON.stringify({name:a.name,description:a.description,dependencies:a.dependencies,npmDependencies:a.npmDependencies,allResolvedDependencies:l},null,2)}]}}),e.tool("search_components","Search Drivn components by name or description",{query:z$1.string().describe("Search query")},async({query:t})=>{let a=t.toLowerCase(),l=v.filter(d=>d.name.includes(a)||d.description.toLowerCase().includes(a));return {content:[{type:"text",text:l.length?JSON.stringify(l.map(d=>({name:d.name,description:d.description})),null,2):`No components matching "${t}".`}]}}),e.tool("get_installation_instructions","Get step-by-step installation instructions for one or more components",{components:z$1.array(z$1.string()).describe("Component names to install"),packageManager:z$1.enum(["npm","pnpm"]).optional().describe("Package manager (default: npm)")},async({components:t,packageManager:a})=>{let l=a??"npm",d=new Set,p=new Set,f=[],g=o=>{if(d.has(o))return;let s=O(o);if(!s){f.push(o);return}s.dependencies.forEach(i=>g(i)),s.npmDependencies.forEach(i=>p.add(i)),d.add(o);};if(t.forEach(g),f.length)return {content:[{type:"text",text:`Unknown components: ${f.join(", ")}. Use list_components to see available components.`}],isError:true};let N=l==="pnpm"?"pnpm dlx":"npx",m=l==="pnpm"?"pnpm add":"npm install",h=[];return h.push(`# Install components via CLI
5069
+ `;var L={version:"1.13.0"};function M(e){return v.find(r=>r.name===e)}function Qe(e){let r=new Set,t=a=>{if(r.has(a))return;let l=M(a);l&&(l.dependencies.forEach(d=>t(d)),r.add(a));};return t(e),r.delete(e),[...r]}async function ze(){let e=new McpServer({name:"drivn",version:L.version});e.tool("list_components","List all available Drivn UI components with descriptions",{},async()=>({content:[{type:"text",text:JSON.stringify(v.map(t=>({name:t.name,description:t.description})),null,2)}]})),e.tool("get_component","Get the full source code and metadata for a Drivn component",{name:z$1.string().describe('Component name (e.g. "button", "dialog")')},async({name:t})=>{let a=M(t);if(!a)return {content:[{type:"text",text:`Component "${t}" not found. Use list_components to see available components.`}],isError:true};let l=R[t];return {content:[{type:"text",text:JSON.stringify({name:a.name,description:a.description,dependencies:a.dependencies,npmDependencies:a.npmDependencies,source:l},null,2)}]}}),e.tool("get_component_metadata","Get metadata only (no source code) for a Drivn component \u2014 useful for planning",{name:z$1.string().describe("Component name")},async({name:t})=>{let a=M(t);if(!a)return {content:[{type:"text",text:`Component "${t}" not found. Use list_components to see available components.`}],isError:true};let l=Qe(t);return {content:[{type:"text",text:JSON.stringify({name:a.name,description:a.description,dependencies:a.dependencies,npmDependencies:a.npmDependencies,allResolvedDependencies:l},null,2)}]}}),e.tool("search_components","Search Drivn components by name or description",{query:z$1.string().describe("Search query")},async({query:t})=>{let a=t.toLowerCase(),l=v.filter(d=>d.name.includes(a)||d.description.toLowerCase().includes(a));return {content:[{type:"text",text:l.length?JSON.stringify(l.map(d=>({name:d.name,description:d.description})),null,2):`No components matching "${t}".`}]}}),e.tool("get_installation_instructions","Get step-by-step installation instructions for one or more components",{components:z$1.array(z$1.string()).describe("Component names to install"),packageManager:z$1.enum(["npm","pnpm"]).optional().describe("Package manager (default: npm)")},async({components:t,packageManager:a})=>{let l=a??"npm",d=new Set,p=new Set,f=[],g=o=>{if(d.has(o))return;let s=M(o);if(!s){f.push(o);return}s.dependencies.forEach(i=>g(i)),s.npmDependencies.forEach(i=>p.add(i)),d.add(o);};if(t.forEach(g),f.length)return {content:[{type:"text",text:`Unknown components: ${f.join(", ")}. Use list_components to see available components.`}],isError:true};let N=l==="pnpm"?"pnpm dlx":"npx",m=l==="pnpm"?"pnpm add":"npm install",h=[];return h.push(`# Install components via CLI
4657
5070
  ${N} drivn@latest add ${[...d].join(" ")}`),p.size&&h.push(`# Install required npm dependencies
4658
5071
  ${m} ${[...p].join(" ")}`),h.push(`# Components will be installed to your configured components directory
4659
5072
  # (default: src/components/ui/)`),{content:[{type:"text",text:JSON.stringify({componentsToInstall:[...d],npmDependencies:[...p],steps:h},null,2)}]}}),e.tool("get_design_tokens","Get the Drivn CSS design tokens (base globals and theme tokens)",{},async()=>({content:[{type:"text",text:`/* === Base Globals === */
4660
5073
  ${C}
4661
5074
 
4662
5075
  /* === Theme Tokens === */
4663
- ${k}`}]})),e.tool("get_drivn_rules","Get Drivn coding conventions and component patterns",{},async()=>({content:[{type:"text",text:j}]})),e.resource("drivn-rules","drivn://rules",{description:"Drivn coding conventions and component patterns"},async()=>({contents:[{uri:"drivn://rules",mimeType:"text/markdown",text:j}]})),e.resource("drivn-design-tokens","drivn://design-tokens",{description:"Drivn CSS globals and theme tokens"},async()=>({contents:[{uri:"drivn://design-tokens",mimeType:"text/css",text:`${C}
5076
+ ${k}`}]})),e.tool("get_drivn_rules","Get Drivn coding conventions and component patterns",{},async()=>({content:[{type:"text",text:z}]})),e.resource("drivn-rules","drivn://rules",{description:"Drivn coding conventions and component patterns"},async()=>({contents:[{uri:"drivn://rules",mimeType:"text/markdown",text:z}]})),e.resource("drivn-design-tokens","drivn://design-tokens",{description:"Drivn CSS globals and theme tokens"},async()=>({contents:[{uri:"drivn://design-tokens",mimeType:"text/css",text:`${C}
4664
5077
 
4665
- ${k}`}]}));for(let t of v){let a=`drivn://components/${t.name}`;e.resource(`drivn-component-${t.name}`,a,{description:t.description},async()=>({contents:[{uri:a,mimeType:"text/plain",text:R[t.name]}]}));}let r=new StdioServerTransport;await e.connect(r);}var I=new Command;I.name("drivn").description("Drivn \u2014 Modern UI components").version(L.version);I.command("create").description("Initialize Drivn in your project").action(Y);I.command("add [components...]").description("Add components to your project").action(Ae);I.command("mcp").description("Start the Drivn MCP server").action(Be);I.parse();
5078
+ ${k}`}]}));for(let t of v){let a=`drivn://components/${t.name}`;e.resource(`drivn-component-${t.name}`,a,{description:t.description},async()=>({contents:[{uri:a,mimeType:"text/plain",text:R[t.name]}]}));}let r=new StdioServerTransport;await e.connect(r);}var I=new Command;I.name("drivn").description("Drivn \u2014 Modern UI components").version(L.version);I.command("create").description("Initialize Drivn in your project").action(W);I.command("add [components...]").description("Add components to your project").action(He);I.command("mcp").description("Start the Drivn MCP server").action(ze);I.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "drivn",
3
- "version": "1.12.0",
3
+ "version": "1.13.0",
4
4
  "description": "Modern UI components for React — add beautiful, accessible components to your project",
5
5
  "license": "MIT",
6
6
  "type": "module",