drivn 1.10.0 → 1.12.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 (2) hide show
  1. package/dist/index.js +589 -29
  2. package/package.json +1 -1
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 m 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 $(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 G="drivn.config.json";function U(e){let r=join(e,G);return existsSync(r)?JSON.parse(readFileSync(r,"utf-8")):null}function K(e,r){let t=join(e,G);writeFileSync(t,JSON.stringify(r,null,2));}function je(e){existsSync(e)||mkdirSync(e,{recursive:true});}function b(e,r){je(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 R(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 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";
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 _e=`import { type ClassValue, clsx } from 'clsx'
139
+ `;var Fe=`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
- `,Fe=["src/app/globals.css","src/styles/globals.css","src/styles/globals.scss","app/globals.css"];function Ge(e){for(let r of Fe)if(x(join(e,r)))return r;return null}async function Y(){let e=process.cwd();console.log(""),console.log(m.bgCyan(m.bold(m.black(" Drivn "))));let r;try{r=$(e),n.log.success(`Detected ${m.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,_e);let g=Ge(e);if(g){let s=await n.confirm({message:`Found ${m.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 ${m.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 ${m.cyan(i)}`));}K(e,d);let N=E(e),u=W(N),h=["clsx","tailwind-merge","lucide-react"],o=n.spinner();o.start("Installing dependencies");try{execSync(R(N,h),{cwd:e,stdio:"ignore"}),o.stop("Dependencies installed");}catch{o.stop("Failed to install dependencies"),n.log.warn(`Run manually: ${R(N,h)}`);}n.log.info(`Add components with: ${m.cyan(`${u} drivn add button`)}`),n.log.info(`Add dark/light theme: ${m.cyan(`${u} drivn add theme`)}`),n.outro("Drivn initialized");}var q=`'use client'
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'
146
146
 
147
147
  import { ThemeProvider as NextThemesProvider } from 'next-themes'
148
148
 
@@ -161,7 +161,7 @@ export function ThemeProvider({
161
161
  </NextThemesProvider>
162
162
  )
163
163
  }
164
- `;var J=`'use client'
164
+ `;var q=`'use client'
165
165
 
166
166
  import * as React from 'react'
167
167
  import { ChevronDown } from 'lucide-react'
@@ -293,7 +293,7 @@ export const Accordion = Object.assign(AccordionRoot, {
293
293
  Trigger,
294
294
  Content
295
295
  })
296
- `;var X=`import * as React from 'react'
296
+ `;var J=`import * as React from 'react'
297
297
  import { cn } from '@/utils/cn'
298
298
 
299
299
  const styles = {
@@ -1646,6 +1646,401 @@ export const Checkbox = React.forwardRef<HTMLInputElement, CheckboxProps>(({
1646
1646
  Checkbox.displayName = 'Checkbox'
1647
1647
  `;var le=`'use client'
1648
1648
 
1649
+ import * as React from 'react'
1650
+ import { Command as CommandPrimitive } from 'cmdk'
1651
+ import { ChevronDown, X, Check, Search } from 'lucide-react'
1652
+ import { cn } from '@/utils/cn'
1653
+
1654
+ const styles = {
1655
+ base: 'relative',
1656
+ trigger: {
1657
+ base: cn(
1658
+ 'flex items-center justify-between w-full min-h-10',
1659
+ 'px-3 gap-2',
1660
+ 'border border-input rounded-[10px] text-sm',
1661
+ 'focus:outline-none transition-colors',
1662
+ 'cursor-pointer'
1663
+ ),
1664
+ singleText: 'flex-1 truncate text-left',
1665
+ multiText: cn(
1666
+ 'flex flex-1 flex-wrap items-center gap-1',
1667
+ 'min-h-[36px] py-1'
1668
+ ),
1669
+ placeholder: 'text-muted-foreground',
1670
+ chevron: cn(
1671
+ 'w-4 h-4 shrink-0 text-muted-foreground',
1672
+ 'transition-transform duration-200'
1673
+ ),
1674
+ clear: cn(
1675
+ 'w-4 h-4 shrink-0 text-muted-foreground',
1676
+ 'hover:text-foreground transition-colors'
1677
+ ),
1678
+ },
1679
+ tag: {
1680
+ base: cn(
1681
+ 'inline-flex items-center gap-1 px-2 py-0.5',
1682
+ 'text-xs rounded-md bg-muted text-foreground'
1683
+ ),
1684
+ remove: cn(
1685
+ 'w-3 h-3 text-muted-foreground',
1686
+ 'hover:text-foreground cursor-pointer'
1687
+ ),
1688
+ },
1689
+ content: cn(
1690
+ 'absolute top-full left-0 right-0 mt-1 z-50',
1691
+ 'bg-card border border-border rounded-[10px]',
1692
+ 'shadow-lg overflow-hidden',
1693
+ 'transition-[opacity,scale] duration-150 ease-out'
1694
+ ),
1695
+ input: {
1696
+ wrapper: cn(
1697
+ 'flex items-center gap-2 px-3',
1698
+ 'border-b border-border'
1699
+ ),
1700
+ icon: 'w-4 h-4 shrink-0 text-muted-foreground',
1701
+ field: cn(
1702
+ 'flex h-10 w-full bg-transparent py-2',
1703
+ 'text-sm text-foreground outline-none',
1704
+ 'placeholder:text-muted-foreground'
1705
+ ),
1706
+ },
1707
+ list: cn(
1708
+ 'max-h-[200px] overflow-y-auto p-1',
1709
+ '[&_[cmdk-list-sizer]]:space-y-0.5'
1710
+ ),
1711
+ empty: cn(
1712
+ 'py-6 text-center text-sm',
1713
+ 'text-muted-foreground'
1714
+ ),
1715
+ group: cn(
1716
+ 'overflow-hidden',
1717
+ '[&_[cmdk-group-heading]]:px-1.5',
1718
+ '[&_[cmdk-group-heading]]:py-1.5',
1719
+ '[&_[cmdk-group-heading]]:text-xs',
1720
+ '[&_[cmdk-group-heading]]:font-medium',
1721
+ '[&_[cmdk-group-heading]]:text-muted-foreground'
1722
+ ),
1723
+ label: cn(
1724
+ 'px-1.5 py-1.5 text-xs font-medium',
1725
+ 'text-muted-foreground'
1726
+ ),
1727
+ item: cn(
1728
+ 'relative flex items-center gap-2 px-2.5 py-1.5',
1729
+ 'text-sm rounded-lg cursor-default select-none',
1730
+ 'data-[selected=true]:bg-accent',
1731
+ 'data-[disabled=true]:pointer-events-none',
1732
+ 'data-[disabled=true]:opacity-50'
1733
+ ),
1734
+ icon: 'w-4 h-4 shrink-0 text-primary ml-auto',
1735
+ separator: 'w-full h-px bg-border',
1736
+ }
1737
+
1738
+ type IconProp = React.ComponentType<{ className?: string }> | React.ReactElement
1739
+
1740
+ interface ComboboxCtx {
1741
+ open: boolean
1742
+ setOpen: (v: boolean) => void
1743
+ multiple: boolean
1744
+ value: string | string[]
1745
+ onSelect: (v: string) => void
1746
+ onClear: () => void
1747
+ }
1748
+
1749
+ function ComboboxRoot({
1750
+ children,
1751
+ value,
1752
+ onChange,
1753
+ multiple = false,
1754
+ className,
1755
+ }: {
1756
+ children: React.ReactNode
1757
+ value?: string | string[]
1758
+ onChange?: (value: string | string[]) => void
1759
+ multiple?: boolean
1760
+ className?: string
1761
+ }) {
1762
+ const [open, setOpen] = React.useState(false)
1763
+ const ref = React.useRef<HTMLDivElement>(null)
1764
+ const close = React.useCallback(() => setOpen(false), [])
1765
+
1766
+ const onSelect = React.useCallback(
1767
+ (v: string) => {
1768
+ if (multiple) {
1769
+ const arr = (value as string[]) ?? []
1770
+ const next = arr.includes(v)
1771
+ ? arr.filter((i) => i !== v)
1772
+ : [...arr, v]
1773
+ onChange?.(next)
1774
+ } else {
1775
+ onChange?.(v)
1776
+ close()
1777
+ }
1778
+ },
1779
+ [multiple, value, onChange, close]
1780
+ )
1781
+
1782
+ const onClear = React.useCallback(() => {
1783
+ onChange?.(multiple ? [] : '')
1784
+ }, [multiple, onChange])
1785
+
1786
+ React.useEffect(() => {
1787
+ const onClick = (e: MouseEvent) => {
1788
+ if (!ref.current?.contains(e.target as Node))
1789
+ close()
1790
+ }
1791
+ document.addEventListener('mousedown', onClick)
1792
+ return () =>
1793
+ document.removeEventListener('mousedown', onClick)
1794
+ }, [close])
1795
+
1796
+ return (
1797
+ <Ctx.Provider
1798
+ value={{
1799
+ open,
1800
+ setOpen,
1801
+ multiple,
1802
+ value: value ?? (multiple ? [] : ''),
1803
+ onSelect,
1804
+ onClear,
1805
+ }}
1806
+ >
1807
+ <div ref={ref} className={cn(styles.base, className)}>
1808
+ {children}
1809
+ </div>
1810
+ </Ctx.Provider>
1811
+ )
1812
+ }
1813
+
1814
+ function Trigger({
1815
+ placeholder = 'Select...',
1816
+ clearable = false,
1817
+ children,
1818
+ className,
1819
+ ...props
1820
+ }: {
1821
+ placeholder?: string
1822
+ clearable?: boolean
1823
+ children?: React.ReactNode
1824
+ className?: string
1825
+ } & Omit<
1826
+ React.ButtonHTMLAttributes<HTMLButtonElement>,
1827
+ 'onClick'
1828
+ >) {
1829
+ const { open, setOpen, multiple, value, onSelect, onClear } = useCombobox()
1830
+
1831
+ const values = Array.isArray(value) ? value : []
1832
+
1833
+ const hasValue = multiple
1834
+ ? values.length > 0
1835
+ : (value as string) !== ''
1836
+
1837
+ return (
1838
+ <button
1839
+ className={cn(styles.trigger.base, className)}
1840
+ onClick={() => setOpen(!open)}
1841
+ {...props}
1842
+ >
1843
+ {multiple ? (
1844
+ <span className={styles.trigger.multiText}>
1845
+ {values.length === 0 ? (
1846
+ <span className={styles.trigger.placeholder}>
1847
+ {placeholder}
1848
+ </span>
1849
+ ) : (
1850
+ <>
1851
+ {values.map((v) => (
1852
+ <span key={v} className={styles.tag.base}>
1853
+ {v}
1854
+ <X
1855
+ className={styles.tag.remove}
1856
+ onMouseDown={(e) => {
1857
+ e.stopPropagation()
1858
+ e.preventDefault()
1859
+ onSelect(v)
1860
+ }}
1861
+ />
1862
+ </span>
1863
+ ))}
1864
+ </>
1865
+ )}
1866
+ </span>
1867
+ ) : (
1868
+ <span
1869
+ className={cn(
1870
+ styles.trigger.singleText,
1871
+ !hasValue && styles.trigger.placeholder
1872
+ )}
1873
+ >
1874
+ {hasValue ? (children ?? value) : placeholder}
1875
+ </span>
1876
+ )}
1877
+ {clearable && hasValue ? (
1878
+ <X
1879
+ className={styles.trigger.clear}
1880
+ onMouseDown={(e) => {
1881
+ e.stopPropagation()
1882
+ e.preventDefault()
1883
+ onClear()
1884
+ }}
1885
+ />
1886
+ ) : (
1887
+ <ChevronDown className={cn(styles.trigger.chevron, open && 'rotate-180')} />
1888
+ )}
1889
+ </button>
1890
+ )
1891
+ }
1892
+
1893
+ function Content({
1894
+ placeholder = 'Search...',
1895
+ children,
1896
+ className,
1897
+ }: {
1898
+ placeholder?: string
1899
+ children: React.ReactNode
1900
+ className?: string
1901
+ }) {
1902
+ const { open } = useCombobox()
1903
+
1904
+ return (
1905
+ <div
1906
+ className={cn(
1907
+ styles.content,
1908
+ open ? 'opacity-100 scale-100' : 'opacity-0 scale-95 pointer-events-none',
1909
+ className
1910
+ )}
1911
+ >
1912
+ <CommandPrimitive key={open ? 'open' : 'closed'} shouldFilter>
1913
+ <div className={styles.input.wrapper}>
1914
+ <Search className={styles.input.icon} />
1915
+ <CommandPrimitive.Input
1916
+ autoFocus
1917
+ className={styles.input.field}
1918
+ placeholder={placeholder}
1919
+ />
1920
+ </div>
1921
+ <CommandPrimitive.List className={styles.list}>
1922
+ {children}
1923
+ </CommandPrimitive.List>
1924
+ </CommandPrimitive>
1925
+ </div>
1926
+ )
1927
+ }
1928
+
1929
+ function Empty({
1930
+ children,
1931
+ className,
1932
+ }: {
1933
+ children?: React.ReactNode
1934
+ className?: string
1935
+ }) {
1936
+ return (
1937
+ <CommandPrimitive.Empty className={cn(styles.empty, className)}>
1938
+ {children ?? 'No results found.'}
1939
+ </CommandPrimitive.Empty>
1940
+ )
1941
+ }
1942
+
1943
+ function Group({
1944
+ heading,
1945
+ children,
1946
+ className,
1947
+ }: {
1948
+ heading?: string
1949
+ children: React.ReactNode
1950
+ className?: string
1951
+ }) {
1952
+ return (
1953
+ <CommandPrimitive.Group
1954
+ heading={heading}
1955
+ className={cn(styles.group, className)}
1956
+ >
1957
+ {children}
1958
+ </CommandPrimitive.Group>
1959
+ )
1960
+ }
1961
+
1962
+ function ComboboxLabel({
1963
+ children,
1964
+ className,
1965
+ }: {
1966
+ children: React.ReactNode
1967
+ className?: string
1968
+ }) {
1969
+ return (
1970
+ <div className={cn(styles.label, className)}>
1971
+ {children}
1972
+ </div>
1973
+ )
1974
+ }
1975
+
1976
+ function Item({
1977
+ value: itemValue,
1978
+ icon: Icon,
1979
+ disabled,
1980
+ children,
1981
+ className,
1982
+ ...props
1983
+ }: {
1984
+ value: string
1985
+ icon?: IconProp
1986
+ disabled?: boolean
1987
+ children: React.ReactNode
1988
+ className?: string
1989
+ } & Omit<
1990
+ React.ComponentProps<typeof CommandPrimitive.Item>,
1991
+ 'onSelect' | 'value'
1992
+ >) {
1993
+ const { value, onSelect, multiple } = useCombobox()
1994
+ const isSelected = multiple
1995
+ ? (value as string[]).includes(itemValue)
1996
+ : value === itemValue
1997
+
1998
+ return (
1999
+ <CommandPrimitive.Item
2000
+ value={itemValue}
2001
+ disabled={disabled}
2002
+ onSelect={() => onSelect(itemValue)}
2003
+ className={cn(styles.item, className)}
2004
+ {...props}
2005
+ >
2006
+ {Icon && (React.isValidElement(Icon) ? Icon : <Icon className="w-4 h-4" />)}
2007
+ {children}
2008
+ {isSelected && (
2009
+ <Check className={styles.icon} />
2010
+ )}
2011
+ </CommandPrimitive.Item>
2012
+ )
2013
+ }
2014
+
2015
+ function ComboboxSeparator({
2016
+ className,
2017
+ }: {
2018
+ className?: string
2019
+ }) {
2020
+ return (
2021
+ <CommandPrimitive.Separator className={cn(styles.separator, className)} />
2022
+ )
2023
+ }
2024
+
2025
+ const Ctx = React.createContext<ComboboxCtx | null>(null)
2026
+
2027
+ function useCombobox() {
2028
+ const ctx = React.useContext(Ctx)
2029
+ if (!ctx) throw new Error('Combobox compound used outside <Combobox>')
2030
+ return ctx
2031
+ }
2032
+
2033
+ export const Combobox = Object.assign(ComboboxRoot, {
2034
+ Trigger,
2035
+ Content,
2036
+ Empty,
2037
+ Group,
2038
+ Label: ComboboxLabel,
2039
+ Item,
2040
+ Separator: ComboboxSeparator,
2041
+ })
2042
+ `;var de=`'use client'
2043
+
1649
2044
  import * as React from 'react'
1650
2045
  import { cn } from '@/utils/cn'
1651
2046
 
@@ -1758,7 +2153,7 @@ export const Collapsible = Object.assign(CollapsibleRoot, {
1758
2153
  Trigger,
1759
2154
  Content,
1760
2155
  })
1761
- `;var de=`'use client'
2156
+ `;var pe=`'use client'
1762
2157
 
1763
2158
  import * as React from 'react'
1764
2159
  import { X } from 'lucide-react'
@@ -1914,7 +2309,7 @@ export const Dialog = Object.assign(DialogRoot, {
1914
2309
  Trigger,
1915
2310
  Content,
1916
2311
  })
1917
- `;var pe=`'use client'
2312
+ `;var ue=`'use client'
1918
2313
 
1919
2314
  import * as React from 'react'
1920
2315
  import { X } from 'lucide-react'
@@ -2331,7 +2726,7 @@ export const Dropdown = Object.assign(DropdownRoot, {
2331
2726
  Label,
2332
2727
  Separator: DropdownSeparator
2333
2728
  })
2334
- `;var ue=`import * as React from 'react'
2729
+ `;var fe=`import * as React from 'react'
2335
2730
  import { cn } from '@/utils/cn'
2336
2731
 
2337
2732
  const styles = {
@@ -2354,7 +2749,7 @@ export const Input = React.forwardRef<HTMLInputElement, InputProps>(({
2354
2749
  )
2355
2750
 
2356
2751
  Input.displayName = 'Input'
2357
- `;var fe=`import * as React from 'react'
2752
+ `;var ge=`import * as React from 'react'
2358
2753
  import { cn } from '@/utils/cn'
2359
2754
 
2360
2755
  const styles = {
@@ -2411,7 +2806,7 @@ function Group({
2411
2806
  }
2412
2807
 
2413
2808
  export const Kbd = Object.assign(KbdRoot, { Group })
2414
- `;var ge=`import * as React from 'react'
2809
+ `;var he=`import * as React from 'react'
2415
2810
  import { cn } from '@/utils/cn'
2416
2811
 
2417
2812
  export function Label({
@@ -2428,7 +2823,7 @@ export function Label({
2428
2823
  />
2429
2824
  )
2430
2825
  }
2431
- `;var he=`import * as React from 'react'
2826
+ `;var be=`import * as React from 'react'
2432
2827
  import { ChevronLeft, ChevronRight, MoreHorizontal } from 'lucide-react'
2433
2828
  import { cn } from '@/utils/cn'
2434
2829
 
@@ -2561,7 +2956,7 @@ export const Pagination = Object.assign(PaginationRoot, {
2561
2956
  Next,
2562
2957
  Ellipsis: PaginationEllipsis,
2563
2958
  })
2564
- `;var be=`'use client'
2959
+ `;var ve=`'use client'
2565
2960
 
2566
2961
  import * as React from 'react'
2567
2962
  import { cn } from '@/utils/cn'
@@ -2666,7 +3061,7 @@ export const Popover = Object.assign(PopoverRoot, {
2666
3061
  Trigger,
2667
3062
  Content
2668
3063
  })
2669
- `;var ve=`import * as React from 'react'
3064
+ `;var xe=`import * as React from 'react'
2670
3065
  import { cn } from '@/utils/cn'
2671
3066
 
2672
3067
  const styles = {
@@ -2704,7 +3099,7 @@ export function Progress({
2704
3099
  </div>
2705
3100
  )
2706
3101
  }
2707
- `;var xe=`'use client'
3102
+ `;var ye=`'use client'
2708
3103
 
2709
3104
  import * as React from 'react'
2710
3105
  import { cn } from '@/utils/cn'
@@ -2853,7 +3248,7 @@ function useRadioGroup() {
2853
3248
  }
2854
3249
 
2855
3250
  export const RadioGroup = Object.assign(RadioGroupRoot, { Item })
2856
- `;var ye=`'use client'
3251
+ `;var Ne=`'use client'
2857
3252
 
2858
3253
  import * as React from 'react'
2859
3254
  import { ChevronDown } from 'lucide-react'
@@ -2945,6 +3340,7 @@ function Trigger({
2945
3340
  const { open, setOpen } = useSelect()
2946
3341
  return (
2947
3342
  <button
3343
+ type="button"
2948
3344
  className={cn(styles.trigger, className)}
2949
3345
  onClick={() => setOpen(!open)}
2950
3346
  {...props}
@@ -2985,6 +3381,7 @@ function Option({
2985
3381
  const { value, onSelect } = useSelect()
2986
3382
  return (
2987
3383
  <button
3384
+ type="button"
2988
3385
  className={cn(styles.option, optValue === value && styles.selected, className)}
2989
3386
  onClick={() => onSelect(optValue)}
2990
3387
  {...props}
@@ -3007,7 +3404,7 @@ export const Select = Object.assign(SelectRoot, {
3007
3404
  Menu,
3008
3405
  Option
3009
3406
  })
3010
- `;var Ne=`import * as React from 'react'
3407
+ `;var Ce=`import * as React from 'react'
3011
3408
  import { cn } from '@/utils/cn'
3012
3409
 
3013
3410
  const styles = {
@@ -3053,7 +3450,7 @@ export function ScrollArea({
3053
3450
  </div>
3054
3451
  )
3055
3452
  }
3056
- `;var Ce=`import * as React from 'react'
3453
+ `;var Re=`import * as React from 'react'
3057
3454
  import { cn } from '@/utils/cn'
3058
3455
 
3059
3456
  const styles = {
@@ -3094,7 +3491,7 @@ export function Skeleton({
3094
3491
  />
3095
3492
  )
3096
3493
  }
3097
- `;var Re=`'use client'
3494
+ `;var ke=`'use client'
3098
3495
 
3099
3496
  import * as React from 'react'
3100
3497
  import { ChevronDown, PanelLeft } from 'lucide-react'
@@ -3380,7 +3777,7 @@ export const Sidebar = Object.assign(SidebarRoot, {
3380
3777
  Separator: SidebarSeparator,
3381
3778
  CollapseButton,
3382
3779
  })
3383
- `;var ke=`'use client'
3780
+ `;var Pe=`'use client'
3384
3781
 
3385
3782
  import * as React from 'react'
3386
3783
  import { cn } from '@/utils/cn'
@@ -3525,7 +3922,7 @@ export const Slider = React.forwardRef<HTMLInputElement, SliderProps>(({
3525
3922
  )
3526
3923
 
3527
3924
  Slider.displayName = 'Slider'
3528
- `;var Pe=`'use client'
3925
+ `;var Se=`'use client'
3529
3926
 
3530
3927
  import * as React from 'react'
3531
3928
  import { cn } from '@/utils/cn'
@@ -3556,6 +3953,7 @@ export function Switch({
3556
3953
  }: SwitchProps) {
3557
3954
  return (
3558
3955
  <button
3956
+ type="button"
3559
3957
  role="switch"
3560
3958
  aria-checked={checked}
3561
3959
  onClick={() => onChange?.(!checked)}
@@ -3680,7 +4078,7 @@ export const Tabs = Object.assign(TabsRoot, {
3680
4078
  Tab,
3681
4079
  Panel
3682
4080
  })
3683
- `;var Se=`import * as React from 'react'
4081
+ `;var Te=`import * as React from 'react'
3684
4082
  import { cn } from '@/utils/cn'
3685
4083
 
3686
4084
  const styles = {
@@ -3707,7 +4105,7 @@ export const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(({
3707
4105
  ))
3708
4106
 
3709
4107
  Textarea.displayName = 'Textarea'
3710
- `;var Te=`'use client'
4108
+ `;var Ie=`'use client'
3711
4109
 
3712
4110
  import * as React from 'react'
3713
4111
  import { Toaster as Sonner, toast } from 'sonner'
@@ -3750,7 +4148,169 @@ function Toaster() {
3750
4148
  }
3751
4149
 
3752
4150
  export { Toaster, toast }
3753
- `;var Ie=`import * as React from 'react'
4151
+ `;var Ee=`'use client'
4152
+
4153
+ import * as React from 'react'
4154
+ import { cn } from '@/utils/cn'
4155
+
4156
+ const styles = {
4157
+ base: cn(
4158
+ 'inline-flex items-center justify-center gap-2',
4159
+ 'rounded-md text-sm font-medium',
4160
+ 'transition-colors cursor-pointer',
4161
+ 'focus:outline-none',
4162
+ 'disabled:opacity-50 disabled:cursor-default'
4163
+ ),
4164
+ variants: {
4165
+ default: cn(
4166
+ 'bg-transparent text-muted-foreground',
4167
+ 'hover:bg-muted hover:text-foreground',
4168
+ 'data-[state=on]:bg-muted',
4169
+ 'data-[state=on]:text-foreground'
4170
+ ),
4171
+ outline: cn(
4172
+ 'border border-border bg-transparent',
4173
+ 'text-muted-foreground',
4174
+ 'hover:border-foreground/20',
4175
+ 'data-[state=on]:bg-muted',
4176
+ 'data-[state=on]:text-foreground',
4177
+ 'data-[state=on]:border-muted'
4178
+ ),
4179
+ },
4180
+ sizes: {
4181
+ sm: 'h-8 px-2.5 text-xs',
4182
+ md: 'h-9 px-3 text-sm',
4183
+ lg: 'h-10 px-4 text-sm',
4184
+ },
4185
+ group: 'inline-flex items-center gap-1',
4186
+ vertical: 'flex-col',
4187
+ }
4188
+
4189
+ interface ToggleGroupCtx {
4190
+ type: 'single' | 'multiple'
4191
+ value: string | string[]
4192
+ onToggle: (v: string) => void
4193
+ disabled?: boolean
4194
+ }
4195
+
4196
+ interface ToggleProps extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'value' | 'onChange'> {
4197
+ pressed?: boolean
4198
+ defaultPressed?: boolean
4199
+ onChange?: (pressed: boolean) => void
4200
+ value?: string
4201
+ variant?: keyof typeof styles.variants
4202
+ size?: keyof typeof styles.sizes
4203
+ }
4204
+
4205
+ const ToggleButton = React.forwardRef<HTMLButtonElement, ToggleProps>(({
4206
+ pressed,
4207
+ defaultPressed,
4208
+ onChange,
4209
+ value,
4210
+ variant = 'default',
4211
+ size = 'md',
4212
+ disabled,
4213
+ className,
4214
+ children,
4215
+ ...props
4216
+ }, ref) => {
4217
+ const ctx = React.useContext(Ctx)
4218
+ const [internal, setInternal] = React.useState(defaultPressed ?? false)
4219
+ const inGroup = ctx !== null && value !== undefined
4220
+
4221
+ const isPressed = inGroup
4222
+ ? ctx.type === 'multiple'
4223
+ ? (ctx.value as string[]).includes(value)
4224
+ : ctx.value === value
4225
+ : pressed ?? internal
4226
+
4227
+ return (
4228
+ <button
4229
+ ref={ref}
4230
+ type="button"
4231
+ aria-pressed={isPressed}
4232
+ data-state={isPressed ? 'on' : 'off'}
4233
+ disabled={disabled ?? (inGroup ? ctx.disabled : false)}
4234
+ className={cn(styles.base, styles.variants[variant], styles.sizes[size], className)}
4235
+ onClick={() => {
4236
+ if (inGroup) {
4237
+ ctx.onToggle(value)
4238
+ } else {
4239
+ const next = !isPressed
4240
+ if (pressed === undefined) setInternal(next)
4241
+ onChange?.(next)
4242
+ }
4243
+ }}
4244
+ {...props}
4245
+ >
4246
+ {children}
4247
+ </button>
4248
+ )
4249
+ })
4250
+
4251
+ ToggleButton.displayName = 'Toggle'
4252
+
4253
+ function ToggleGroupRoot({
4254
+ children,
4255
+ type,
4256
+ defaultValue,
4257
+ value: controlledValue,
4258
+ onValueChange,
4259
+ orientation = 'horizontal',
4260
+ disabled,
4261
+ className,
4262
+ }: {
4263
+ children: React.ReactNode
4264
+ type: 'single' | 'multiple'
4265
+ defaultValue?: string | string[]
4266
+ value?: string | string[]
4267
+ onValueChange?: (value: string | string[]) => void
4268
+ orientation?: 'vertical' | 'horizontal'
4269
+ disabled?: boolean
4270
+ className?: string
4271
+ }) {
4272
+ const [internal, setInternal] = React.useState<string | string[]>(defaultValue ?? (type === 'multiple' ? [] : ''))
4273
+ const isControlled = controlledValue !== undefined
4274
+ const current = isControlled ? controlledValue : internal
4275
+
4276
+ const onToggle = (itemValue: string) => {
4277
+ let next: string | string[]
4278
+ if (type === 'single') {
4279
+ next = current === itemValue ? '' : itemValue
4280
+ } else {
4281
+ const arr = current as string[]
4282
+ next = arr.includes(itemValue)
4283
+ ? arr.filter((v) => v !== itemValue)
4284
+ : [...arr, itemValue]
4285
+ }
4286
+ if (!isControlled) setInternal(next)
4287
+ onValueChange?.(next)
4288
+ }
4289
+
4290
+ return (
4291
+ <Ctx.Provider
4292
+ value={{ type, value: current, onToggle, disabled }}
4293
+ >
4294
+ <div
4295
+ role="group"
4296
+ className={cn(
4297
+ styles.group,
4298
+ orientation === 'vertical' && styles.vertical,
4299
+ className
4300
+ )}
4301
+ >
4302
+ {children}
4303
+ </div>
4304
+ </Ctx.Provider>
4305
+ )
4306
+ }
4307
+
4308
+ const Ctx = React.createContext<ToggleGroupCtx | null>(null)
4309
+
4310
+ export const Toggle = Object.assign(ToggleButton, {
4311
+ Group: ToggleGroupRoot,
4312
+ })
4313
+ `;var Le=`import * as React from 'react'
3754
4314
  import { cn } from '@/utils/cn'
3755
4315
 
3756
4316
  const styles = {
@@ -3924,7 +4484,7 @@ export const Table = Object.assign(TableRoot, {
3924
4484
  Head,
3925
4485
  Cell,
3926
4486
  })
3927
- `;var Ee=`import * as React from 'react'
4487
+ `;var Oe=`import * as React from 'react'
3928
4488
  import { cn } from '@/utils/cn'
3929
4489
 
3930
4490
  const styles = {
@@ -3969,7 +4529,7 @@ export function Tooltip({
3969
4529
  </span>
3970
4530
  )
3971
4531
  }
3972
- `;var Le=`
4532
+ `;var Me=`
3973
4533
  /* react-day-picker theme integration */
3974
4534
  .rdp-root {
3975
4535
  --rdp-accent-color: var(--primary);
@@ -3980,7 +4540,7 @@ export function Tooltip({
3980
4540
  --rdp-selected-border: none;
3981
4541
  --rdp-day_button-border: none;
3982
4542
  }
3983
- `,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:"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:"tooltip",description:"Pure CSS tooltip with 4 position options",dependencies:[],npmDependencies:[]}],w={accordion:J,alert:X,"aspect-ratio":Z,avatar:Q,badge:ee,breadcrumb:te,button:ne,calendar:oe,"date-picker":re,command:se,carousel:ae,card:ie,checkbox:ce,collapsible:le,dialog:de,drawer:pe,dropdown:me,input:ue,kbd:fe,label:ge,pagination:he,popover:be,progress:ve,"radio-group":xe,select:ye,"scroll-area":Ne,separator:Ce,skeleton:we,sidebar:Re,slider:ke,switch:Pe,table:Ie,tabs:De,textarea:Se,theme:q,toast:Te,tooltip:Ee};async function Oe(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 u=t.typescript?"tsx":"jsx",h=join(r,t.paths.components);for(let o of p){let s=join(h,`${o}.${u}`);if(x(s)){let D=await n.confirm({message:`${o}.${u} exists. Overwrite?`,initialValue:false});if(n.isCancel(D)||!D){n.log.warn(`Skipped ${o}`);continue}}let i=w[o];i=i.replace(/@\/utils/g,`@/${t.paths.utils.replace(/^src\//,"")}`),b(s,i),n.log.success(`${o} \u2192 ${t.paths.components}/${o}.${u}`);}if(l){let o=join(h,`theme-provider.${u}`);if(x(o)){let i=await n.confirm({message:`theme-provider.${u} exists. Overwrite?`,initialValue:false});!n.isCancel(i)&&i?(b(o,w.theme),n.log.success(`theme-provider \u2192 ${t.paths.components}/theme-provider.${u}`)):n.log.warn("Skipped theme-provider");}else b(o,w.theme),n.log.success(`theme-provider \u2192 ${t.paths.components}/theme-provider.${u}`);if(t.paths.globals){let i=join(r,t.paths.globals);if(x(i)){let D=H(i);D.includes('[data-theme="dark"]')?n.log.warn("Theme tokens already exist in globals \u2014 skipped"):(b(i,D+k),n.log.success(`Theme tokens appended to ${m.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(m.bold("Complete the setup:")),n.log.message(""),n.log.message(m.bold(`${m.cyan("1.")} Import ThemeProvider in your root layout:`)),n.log.message(m.cyan(` import { ThemeProvider } from "${s}/theme-provider"`)),n.log.message(""),n.log.message(m.bold(`${m.cyan("2.")} Add suppressHydrationWarning to <html>:`)),n.log.message(m.cyan(" <html suppressHydrationWarning>")),n.log.message(""),n.log.message(m.bold(`${m.cyan("3.")} Wrap your app with ThemeProvider:`)),n.log.message(m.cyan(" <ThemeProvider>")),n.log.message(m.cyan(" {children}")),n.log.message(m.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+Le),n.log.success(`Calendar tokens appended to ${m.cyan(t.paths.globals)}`));}}if(f.size){let o=E(r),s=[...f],i=n.spinner();i.start("Installing packages");try{execSync(R(o,s),{cwd:r,stdio:"ignore"}),i.stop("Packages installed");}catch{i.stop("Failed to install packages"),n.log.warn(`Run manually: ${R(o,s)}`);}}n.outro("Done.");}var j=`# Drivn Component Conventions
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
3984
4544
 
3985
4545
  ## Core Philosophy
3986
4546
  - **Zero runtime UI deps** \u2014 No Radix, no cva, no external UI primitives. Pure React + Tailwind.
@@ -4093,13 +4653,13 @@ import { cn } from '@/utils/cn'
4093
4653
  - Components declare internal deps (other Drivn components)
4094
4654
  - Some components need npm packages (react-day-picker, cmdk, embla-carousel-react, sonner)
4095
4655
  - The CLI resolves and installs all dependencies automatically
4096
- `;var L={version:"1.10.0"};function O(e){return v.find(r=>r.name===e)}function qe(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 Me(){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=w[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=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=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",u=l==="pnpm"?"pnpm add":"npm install",h=[];return h.push(`# Install components via CLI
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
4097
4657
  ${N} drivn@latest add ${[...d].join(" ")}`),p.size&&h.push(`# Install required npm dependencies
4098
- ${u} ${[...p].join(" ")}`),h.push(`# Components will be installed to your configured components directory
4658
+ ${m} ${[...p].join(" ")}`),h.push(`# Components will be installed to your configured components directory
4099
4659
  # (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 === */
4100
4660
  ${C}
4101
4661
 
4102
4662
  /* === Theme Tokens === */
4103
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}
4104
4664
 
4105
- ${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:w[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(Oe);I.command("mcp").description("Start the Drivn MCP server").action(Me);I.parse();
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();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "drivn",
3
- "version": "1.10.0",
3
+ "version": "1.12.0",
4
4
  "description": "Modern UI components for React — add beautiful, accessible components to your project",
5
5
  "license": "MIT",
6
6
  "type": "module",