drivn 1.4.0 → 1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +446 -15
- 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 e from'@clack/prompts';import i from'picocolors';import {join,dirname}from'path';import {execSync}from'child_process';import {existsSync,readFileSync,writeFileSync,mkdirSync}from'fs';var A={next:"Next.js",react:"React"};function B(t){let
|
|
2
|
+
import {Command}from'commander';import*as e from'@clack/prompts';import i from'picocolors';import {join,dirname}from'path';import {execSync}from'child_process';import {existsSync,readFileSync,writeFileSync,mkdirSync}from'fs';var A={next:"Next.js",react:"React"};function B(t){let o=join(t,"package.json");if(!existsSync(o))throw new Error("package.json not found");let a=JSON.parse(readFileSync(o,"utf-8")),b={...a.dependencies,...a.devDependencies},p="react";b.next&&(p="next");let g=existsSync(join(t,"src")),u=existsSync(join(t,"tsconfig.json"));return {framework:p,srcDir:g,typescript:u}}var V="drivn.config.json";function $(t){let o=join(t,V);return existsSync(o)?JSON.parse(readFileSync(o,"utf-8")):null}function _(t,o){let a=join(t,V);writeFileSync(a,JSON.stringify(o,null,2));}function Te(t){existsSync(t)||mkdirSync(t,{recursive:true});}function d(t,o){Te(dirname(t)),writeFileSync(t,o);}function M(t){return readFileSync(t,"utf-8")}function m(t){return existsSync(t)}function P(t){return existsSync(join(t,"pnpm-lock.yaml"))?"pnpm":"npm"}function y(t,o){let a=o.join(" ");return t==="pnpm"?`pnpm add ${a}`:`npm install ${a}`}function F(t){return t==="pnpm"?"pnpm dlx":"npx"}var S=`@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
|
|
139
|
+
`;var Me=`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
|
-
`,
|
|
145
|
+
`,Oe=["src/app/globals.css","src/styles/globals.css","src/styles/globals.scss","app/globals.css"];function Ae(t){for(let o of Oe)if(m(join(t,o)))return o;return null}async function G(){let t=process.cwd();console.log(""),console.log(i.bgCyan(i.bold(i.black(" Drivn "))));let o;try{o=B(t),e.log.success(`Detected ${i.cyan(A[o.framework])}`);}catch{e.log.error("No package.json found. Run this command in a project directory."),e.outro("Setup cancelled"),process.exit(1);}if(m(join(t,"drivn.config.json"))){let r=await e.confirm({message:"Config already exists. Overwrite?",initialValue:false});(e.isCancel(r)||!r)&&(e.cancel("Setup cancelled"),process.exit(0));}let a=o.srcDir?"src/components/ui":"components/ui",b=o.srcDir?"src/utils":"utils",p=await e.group({components:()=>e.text({message:"Where should components be installed?",placeholder:a,defaultValue:a}),utils:()=>e.text({message:"Where should utilities be placed?",placeholder:b,defaultValue:b})},{onCancel:()=>{e.cancel("Setup cancelled"),process.exit(0);}}),g={framework:o.framework,typescript:o.typescript,paths:{components:p.components,utils:p.utils},installed:[]},u=o.typescript?"ts":"js",v=join(t,p.utils,`cn.${u}`);m(v)||d(v,Me);let h=Ae(t);if(h){let r=await e.confirm({message:`Found ${i.cyan(h)}. Add Drivn color tokens?`,initialValue:true});!e.isCancel(r)&&r&&(d(join(t,h),S),g.paths.globals=h,e.log.success(`Color tokens written to ${i.cyan(h)}`));}else {let r=o.srcDir?"src/styles/globals.css":"styles/globals.css",c=await e.text({message:"Where should the globals CSS file be created?",placeholder:r,defaultValue:r});e.isCancel(c)||(d(join(t,c),S),g.paths.globals=c,e.log.success(`Color tokens written to ${i.cyan(c)}`));}_(t,g);let x=P(t),l=F(x),N=["clsx","tailwind-merge","lucide-react"],n=e.spinner();n.start("Installing dependencies");try{execSync(y(x,N),{cwd:t,stdio:"ignore"}),n.stop("Dependencies installed");}catch{n.stop("Failed to install dependencies"),e.log.warn(`Run manually: ${y(x,N)}`);}e.log.info(`Add components with: ${i.cyan(`${l} drivn add button`)}`),e.log.info(`Add dark/light theme: ${i.cyan(`${l} drivn add theme`)}`),e.outro("Drivn initialized");}var K=`'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
|
|
164
|
+
`;var U=`'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
|
|
296
|
+
`;var Y=`import * as React from 'react'
|
|
297
297
|
import { cn } from '@/utils/cn'
|
|
298
298
|
|
|
299
299
|
const styles = {
|
|
@@ -341,7 +341,7 @@ export function Alert({
|
|
|
341
341
|
</div>
|
|
342
342
|
)
|
|
343
343
|
}
|
|
344
|
-
`;var
|
|
344
|
+
`;var W=`import * as React from 'react'
|
|
345
345
|
import { cn } from '@/utils/cn'
|
|
346
346
|
|
|
347
347
|
const styles = {
|
|
@@ -1491,7 +1491,7 @@ export const Carousel = Object.assign(CarouselRoot, {
|
|
|
1491
1491
|
Next,
|
|
1492
1492
|
Dots
|
|
1493
1493
|
})
|
|
1494
|
-
`;var
|
|
1494
|
+
`;var ne=`import * as React from 'react'
|
|
1495
1495
|
import { cn } from '@/utils/cn'
|
|
1496
1496
|
|
|
1497
1497
|
const styles = {
|
|
@@ -1558,7 +1558,7 @@ export const Card = Object.assign(CardRoot, {
|
|
|
1558
1558
|
Preview,
|
|
1559
1559
|
Info
|
|
1560
1560
|
})
|
|
1561
|
-
`;var
|
|
1561
|
+
`;var oe=`'use client'
|
|
1562
1562
|
|
|
1563
1563
|
import * as React from 'react'
|
|
1564
1564
|
import { Check } from 'lucide-react'
|
|
@@ -2680,6 +2680,437 @@ export function Separator({
|
|
|
2680
2680
|
}
|
|
2681
2681
|
`;var ge=`'use client'
|
|
2682
2682
|
|
|
2683
|
+
import * as React from 'react'
|
|
2684
|
+
import { ChevronDown, PanelLeft } from 'lucide-react'
|
|
2685
|
+
import { cn } from '@/utils/cn'
|
|
2686
|
+
|
|
2687
|
+
const styles = {
|
|
2688
|
+
base: cn(
|
|
2689
|
+
'flex flex-col h-full bg-card border-border overflow-hidden',
|
|
2690
|
+
'transition-[width] duration-200 ease-in-out'
|
|
2691
|
+
),
|
|
2692
|
+
variants: {
|
|
2693
|
+
default: 'border-r',
|
|
2694
|
+
floating: cn(
|
|
2695
|
+
'border rounded-xl shadow-lg m-2',
|
|
2696
|
+
'h-[calc(100%-16px)]'
|
|
2697
|
+
),
|
|
2698
|
+
},
|
|
2699
|
+
width: {
|
|
2700
|
+
expanded: 'w-[240px]',
|
|
2701
|
+
collapsed: 'w-[60px]',
|
|
2702
|
+
},
|
|
2703
|
+
header: cn(
|
|
2704
|
+
'flex items-center gap-2 px-3 py-3',
|
|
2705
|
+
'border-b border-border shrink-0'
|
|
2706
|
+
),
|
|
2707
|
+
content: 'flex-1 overflow-y-auto px-2 py-2 flex flex-col gap-1',
|
|
2708
|
+
footer: cn(
|
|
2709
|
+
'flex items-center mt-auto px-3 py-3',
|
|
2710
|
+
'border-t border-border shrink-0'
|
|
2711
|
+
),
|
|
2712
|
+
group: 'py-2',
|
|
2713
|
+
groupHeading: cn(
|
|
2714
|
+
'flex items-center justify-between w-full',
|
|
2715
|
+
'px-2 py-1.5 text-xs font-medium text-muted-foreground',
|
|
2716
|
+
'hover:text-foreground/80 transition-colors cursor-pointer'
|
|
2717
|
+
),
|
|
2718
|
+
groupIcon: cn(
|
|
2719
|
+
'w-3 h-3 text-muted-foreground/60',
|
|
2720
|
+
'transition-transform duration-200'
|
|
2721
|
+
),
|
|
2722
|
+
groupPanel: 'grid transition-[grid-template-rows] duration-200',
|
|
2723
|
+
groupContent: 'overflow-hidden flex flex-col gap-1',
|
|
2724
|
+
item: cn(
|
|
2725
|
+
'flex items-center gap-3 w-full px-2 py-2',
|
|
2726
|
+
'text-sm text-muted-foreground rounded-lg',
|
|
2727
|
+
'hover:bg-accent hover:text-foreground',
|
|
2728
|
+
'transition-colors cursor-pointer'
|
|
2729
|
+
),
|
|
2730
|
+
itemActive: 'bg-accent text-foreground font-medium',
|
|
2731
|
+
itemIcon: 'w-4 h-4 shrink-0',
|
|
2732
|
+
itemBadge: cn(
|
|
2733
|
+
'ml-auto text-xs font-medium px-1.5 py-0.5',
|
|
2734
|
+
'rounded-md bg-primary/10 text-primary'
|
|
2735
|
+
),
|
|
2736
|
+
separator: 'mx-2 my-2 h-px border-0 bg-muted',
|
|
2737
|
+
collapseBtn: cn(
|
|
2738
|
+
'flex items-center justify-center',
|
|
2739
|
+
'w-7 h-7 rounded-md ml-auto shrink-0',
|
|
2740
|
+
'text-muted-foreground hover:text-foreground',
|
|
2741
|
+
'hover:bg-accent transition-colors cursor-pointer'
|
|
2742
|
+
),
|
|
2743
|
+
}
|
|
2744
|
+
|
|
2745
|
+
type Variant = keyof typeof styles.variants
|
|
2746
|
+
type Side = 'left' | 'right'
|
|
2747
|
+
type IconProp = React.ComponentType<{ className?: string }> | React.ReactElement
|
|
2748
|
+
|
|
2749
|
+
interface SidebarCtx {
|
|
2750
|
+
collapsed: boolean
|
|
2751
|
+
setCollapsed: (v: boolean) => void
|
|
2752
|
+
variant: Variant
|
|
2753
|
+
side: Side
|
|
2754
|
+
}
|
|
2755
|
+
|
|
2756
|
+
function SidebarRoot({
|
|
2757
|
+
children,
|
|
2758
|
+
defaultCollapsed = false,
|
|
2759
|
+
collapsed: controlled,
|
|
2760
|
+
onCollapsedChange,
|
|
2761
|
+
variant = 'default',
|
|
2762
|
+
side = 'left',
|
|
2763
|
+
className,
|
|
2764
|
+
}: {
|
|
2765
|
+
children: React.ReactNode
|
|
2766
|
+
defaultCollapsed?: boolean
|
|
2767
|
+
collapsed?: boolean
|
|
2768
|
+
onCollapsedChange?: (collapsed: boolean) => void
|
|
2769
|
+
variant?: Variant
|
|
2770
|
+
side?: Side
|
|
2771
|
+
className?: string
|
|
2772
|
+
}) {
|
|
2773
|
+
const [uncontrolled, setUncontrolled] = React.useState(defaultCollapsed)
|
|
2774
|
+
const collapsed = controlled ?? uncontrolled
|
|
2775
|
+
const setCollapsed = React.useCallback(
|
|
2776
|
+
(v: boolean) => {
|
|
2777
|
+
onCollapsedChange?.(v)
|
|
2778
|
+
if (controlled === undefined) setUncontrolled(v)
|
|
2779
|
+
},
|
|
2780
|
+
[controlled, onCollapsedChange]
|
|
2781
|
+
)
|
|
2782
|
+
|
|
2783
|
+
return (
|
|
2784
|
+
<Ctx.Provider value={{ collapsed, setCollapsed, variant, side }}>
|
|
2785
|
+
<aside
|
|
2786
|
+
className={cn(styles.base, styles.variants[variant], collapsed ? styles.width.collapsed : styles.width.expanded, className)}
|
|
2787
|
+
>
|
|
2788
|
+
{children}
|
|
2789
|
+
</aside>
|
|
2790
|
+
</Ctx.Provider>
|
|
2791
|
+
)
|
|
2792
|
+
}
|
|
2793
|
+
|
|
2794
|
+
function Header({
|
|
2795
|
+
children,
|
|
2796
|
+
className,
|
|
2797
|
+
}: {
|
|
2798
|
+
children: React.ReactNode
|
|
2799
|
+
className?: string
|
|
2800
|
+
}) {
|
|
2801
|
+
const { collapsed } = useSidebar()
|
|
2802
|
+
return (
|
|
2803
|
+
<div className={cn(styles.header, collapsed && 'justify-center px-2 gap-0', className)}>
|
|
2804
|
+
{children}
|
|
2805
|
+
</div>
|
|
2806
|
+
)
|
|
2807
|
+
}
|
|
2808
|
+
|
|
2809
|
+
function CollapseButton({
|
|
2810
|
+
className,
|
|
2811
|
+
}: {
|
|
2812
|
+
className?: string
|
|
2813
|
+
}) {
|
|
2814
|
+
const { collapsed, setCollapsed } = useSidebar()
|
|
2815
|
+
return (
|
|
2816
|
+
<button
|
|
2817
|
+
aria-label={collapsed ? 'Expand sidebar' : 'Collapse sidebar'}
|
|
2818
|
+
className={cn(styles.collapseBtn, collapsed && 'ml-0', className)}
|
|
2819
|
+
onClick={() => setCollapsed(!collapsed)}
|
|
2820
|
+
>
|
|
2821
|
+
<PanelLeft className={cn('w-4 h-4 transition-transform duration-200', collapsed && 'rotate-180')} />
|
|
2822
|
+
</button>
|
|
2823
|
+
)
|
|
2824
|
+
}
|
|
2825
|
+
|
|
2826
|
+
function SidebarContent({
|
|
2827
|
+
children,
|
|
2828
|
+
className,
|
|
2829
|
+
}: {
|
|
2830
|
+
children: React.ReactNode
|
|
2831
|
+
className?: string
|
|
2832
|
+
}) {
|
|
2833
|
+
return (
|
|
2834
|
+
<div className={cn(styles.content, className)}>
|
|
2835
|
+
{children}
|
|
2836
|
+
</div>
|
|
2837
|
+
)
|
|
2838
|
+
}
|
|
2839
|
+
|
|
2840
|
+
function Footer({
|
|
2841
|
+
children,
|
|
2842
|
+
className,
|
|
2843
|
+
}: {
|
|
2844
|
+
children: React.ReactNode
|
|
2845
|
+
className?: string
|
|
2846
|
+
}) {
|
|
2847
|
+
const { collapsed } = useSidebar()
|
|
2848
|
+
return (
|
|
2849
|
+
<div className={cn(styles.footer, collapsed && 'px-2 justify-center overflow-hidden', className)}>
|
|
2850
|
+
{children}
|
|
2851
|
+
</div>
|
|
2852
|
+
)
|
|
2853
|
+
}
|
|
2854
|
+
|
|
2855
|
+
function Group({
|
|
2856
|
+
children,
|
|
2857
|
+
heading,
|
|
2858
|
+
defaultOpen = true,
|
|
2859
|
+
collapsible = true,
|
|
2860
|
+
className,
|
|
2861
|
+
}: {
|
|
2862
|
+
children: React.ReactNode
|
|
2863
|
+
heading?: string
|
|
2864
|
+
defaultOpen?: boolean
|
|
2865
|
+
collapsible?: boolean
|
|
2866
|
+
className?: string
|
|
2867
|
+
}) {
|
|
2868
|
+
const [open, setOpen] = React.useState(defaultOpen)
|
|
2869
|
+
const { collapsed } = useSidebar()
|
|
2870
|
+
|
|
2871
|
+
return (
|
|
2872
|
+
<div className={cn(styles.group, className)}>
|
|
2873
|
+
{heading && !collapsed && (
|
|
2874
|
+
collapsible ? (
|
|
2875
|
+
<button
|
|
2876
|
+
className={styles.groupHeading}
|
|
2877
|
+
onClick={() => setOpen(!open)}
|
|
2878
|
+
>
|
|
2879
|
+
{heading}
|
|
2880
|
+
<ChevronDown className={cn(styles.groupIcon, open && 'rotate-180')} />
|
|
2881
|
+
</button>
|
|
2882
|
+
) : (
|
|
2883
|
+
<span className={styles.groupHeading}>
|
|
2884
|
+
{heading}
|
|
2885
|
+
</span>
|
|
2886
|
+
)
|
|
2887
|
+
)}
|
|
2888
|
+
<div
|
|
2889
|
+
className={styles.groupPanel}
|
|
2890
|
+
style={{ gridTemplateRows: !heading || open || collapsed ? '1fr' : '0fr' }}
|
|
2891
|
+
>
|
|
2892
|
+
<div className={styles.groupContent}>
|
|
2893
|
+
{children}
|
|
2894
|
+
</div>
|
|
2895
|
+
</div>
|
|
2896
|
+
</div>
|
|
2897
|
+
)
|
|
2898
|
+
}
|
|
2899
|
+
|
|
2900
|
+
function Item({
|
|
2901
|
+
children,
|
|
2902
|
+
icon: Icon,
|
|
2903
|
+
active,
|
|
2904
|
+
badge,
|
|
2905
|
+
className,
|
|
2906
|
+
...props
|
|
2907
|
+
}: {
|
|
2908
|
+
children: React.ReactNode
|
|
2909
|
+
icon?: IconProp
|
|
2910
|
+
active?: boolean
|
|
2911
|
+
badge?: string | number
|
|
2912
|
+
className?: string
|
|
2913
|
+
} & React.ButtonHTMLAttributes<HTMLButtonElement>) {
|
|
2914
|
+
const { collapsed } = useSidebar()
|
|
2915
|
+
return (
|
|
2916
|
+
<button
|
|
2917
|
+
className={cn(styles.item, active && styles.itemActive, collapsed && 'justify-center px-0', className)}
|
|
2918
|
+
title={collapsed ? String(children) : undefined}
|
|
2919
|
+
{...props}
|
|
2920
|
+
>
|
|
2921
|
+
{Icon && (
|
|
2922
|
+
React.isValidElement(Icon)
|
|
2923
|
+
? Icon
|
|
2924
|
+
: <Icon className={styles.itemIcon} />
|
|
2925
|
+
)}
|
|
2926
|
+
{!collapsed && (
|
|
2927
|
+
<>
|
|
2928
|
+
<span className="truncate">{children}</span>
|
|
2929
|
+
{badge !== undefined && (
|
|
2930
|
+
<span className={styles.itemBadge}>
|
|
2931
|
+
{badge}
|
|
2932
|
+
</span>
|
|
2933
|
+
)}
|
|
2934
|
+
</>
|
|
2935
|
+
)}
|
|
2936
|
+
</button>
|
|
2937
|
+
)
|
|
2938
|
+
}
|
|
2939
|
+
|
|
2940
|
+
function SidebarSeparator({
|
|
2941
|
+
className,
|
|
2942
|
+
}: {
|
|
2943
|
+
className?: string
|
|
2944
|
+
}) {
|
|
2945
|
+
return <hr className={cn(styles.separator, className)} />
|
|
2946
|
+
}
|
|
2947
|
+
|
|
2948
|
+
const Ctx = React.createContext<SidebarCtx | null>(null)
|
|
2949
|
+
|
|
2950
|
+
function useSidebar() {
|
|
2951
|
+
const ctx = React.useContext(Ctx)
|
|
2952
|
+
if (!ctx) throw new Error('Sidebar compound used outside <Sidebar>')
|
|
2953
|
+
return ctx
|
|
2954
|
+
}
|
|
2955
|
+
|
|
2956
|
+
export { useSidebar }
|
|
2957
|
+
|
|
2958
|
+
export const Sidebar = Object.assign(SidebarRoot, {
|
|
2959
|
+
Header,
|
|
2960
|
+
Content: SidebarContent,
|
|
2961
|
+
Footer,
|
|
2962
|
+
Group,
|
|
2963
|
+
Item,
|
|
2964
|
+
Separator: SidebarSeparator,
|
|
2965
|
+
CollapseButton,
|
|
2966
|
+
})
|
|
2967
|
+
`;var he=`'use client'
|
|
2968
|
+
|
|
2969
|
+
import * as React from 'react'
|
|
2970
|
+
import { cn } from '@/utils/cn'
|
|
2971
|
+
|
|
2972
|
+
const styles = {
|
|
2973
|
+
base: 'relative cursor-pointer touch-none select-none',
|
|
2974
|
+
track: 'relative bg-border rounded-full',
|
|
2975
|
+
range: 'absolute bg-foreground rounded-full',
|
|
2976
|
+
thumb: cn(
|
|
2977
|
+
'absolute rounded-full bg-foreground shadow-sm',
|
|
2978
|
+
'cursor-grab active:cursor-grabbing'
|
|
2979
|
+
),
|
|
2980
|
+
horizontal: {
|
|
2981
|
+
base: 'w-full',
|
|
2982
|
+
track: 'w-full',
|
|
2983
|
+
range: 'inset-y-0 left-0',
|
|
2984
|
+
thumb: 'top-1/2 -translate-x-1/2 -translate-y-1/2',
|
|
2985
|
+
},
|
|
2986
|
+
vertical: {
|
|
2987
|
+
base: 'h-48',
|
|
2988
|
+
track: 'h-full',
|
|
2989
|
+
range: 'inset-x-0 bottom-0',
|
|
2990
|
+
thumb: 'left-1/2 -translate-x-1/2 translate-y-1/2',
|
|
2991
|
+
},
|
|
2992
|
+
sizes: {
|
|
2993
|
+
sm: { track: 'h-1', thumb: 'w-3 h-3', vTrack: 'w-1' },
|
|
2994
|
+
md: { track: 'h-1.5', thumb: 'w-4 h-4', vTrack: 'w-1.5' },
|
|
2995
|
+
lg: { track: 'h-2', thumb: 'w-5 h-5', vTrack: 'w-2' },
|
|
2996
|
+
},
|
|
2997
|
+
disabled: 'opacity-50 cursor-default pointer-events-none',
|
|
2998
|
+
}
|
|
2999
|
+
|
|
3000
|
+
interface SliderProps extends Omit<
|
|
3001
|
+
React.HTMLAttributes<HTMLDivElement>,
|
|
3002
|
+
'onChange' | 'defaultValue'
|
|
3003
|
+
> {
|
|
3004
|
+
value?: number
|
|
3005
|
+
defaultValue?: number
|
|
3006
|
+
min?: number
|
|
3007
|
+
max?: number
|
|
3008
|
+
step?: number
|
|
3009
|
+
orientation?: 'horizontal' | 'vertical'
|
|
3010
|
+
onChange?: (value: number) => void
|
|
3011
|
+
disabled?: boolean
|
|
3012
|
+
size?: keyof typeof styles.sizes
|
|
3013
|
+
name?: string
|
|
3014
|
+
}
|
|
3015
|
+
|
|
3016
|
+
function snap(val: number, min: number, step: number) {
|
|
3017
|
+
return Math.round((val - min) / step) * step + min
|
|
3018
|
+
}
|
|
3019
|
+
|
|
3020
|
+
export const Slider = React.forwardRef<HTMLInputElement, SliderProps>(({
|
|
3021
|
+
value,
|
|
3022
|
+
defaultValue = 0,
|
|
3023
|
+
min = 0,
|
|
3024
|
+
max = 100,
|
|
3025
|
+
step = 1,
|
|
3026
|
+
orientation = 'horizontal',
|
|
3027
|
+
onChange,
|
|
3028
|
+
disabled,
|
|
3029
|
+
size = 'md',
|
|
3030
|
+
name,
|
|
3031
|
+
className,
|
|
3032
|
+
...props
|
|
3033
|
+
}, ref) => {
|
|
3034
|
+
const [internal, setInternal] = React.useState(defaultValue)
|
|
3035
|
+
const isControlled = value !== undefined
|
|
3036
|
+
const current = isControlled ? value : internal
|
|
3037
|
+
const trackRef = React.useRef<HTMLDivElement>(null)
|
|
3038
|
+
|
|
3039
|
+
const isH = orientation === 'horizontal'
|
|
3040
|
+
const s = styles.sizes[size]
|
|
3041
|
+
const dir = isH ? styles.horizontal : styles.vertical
|
|
3042
|
+
const pct = (Math.min(Math.max(current, min), max) - min) / (max - min) * 100
|
|
3043
|
+
|
|
3044
|
+
function resolve(x: number, y: number) {
|
|
3045
|
+
const el = trackRef.current
|
|
3046
|
+
if (!el) return
|
|
3047
|
+
const r = el.getBoundingClientRect()
|
|
3048
|
+
const ratio = isH
|
|
3049
|
+
? (x - r.left) / r.width
|
|
3050
|
+
: 1 - (y - r.top) / r.height
|
|
3051
|
+
const raw = min + ratio * (max - min)
|
|
3052
|
+
const clamped = Math.min(Math.max(snap(raw, min, step), min), max)
|
|
3053
|
+
if (!isControlled) setInternal(clamped)
|
|
3054
|
+
onChange?.(clamped)
|
|
3055
|
+
}
|
|
3056
|
+
|
|
3057
|
+
function handlePointerDown(e: React.PointerEvent) {
|
|
3058
|
+
if (disabled) return
|
|
3059
|
+
e.preventDefault()
|
|
3060
|
+
resolve(e.clientX, e.clientY)
|
|
3061
|
+
const onMove = (ev: PointerEvent) =>
|
|
3062
|
+
resolve(ev.clientX, ev.clientY)
|
|
3063
|
+
const onUp = () => {
|
|
3064
|
+
document.removeEventListener('pointermove', onMove)
|
|
3065
|
+
document.removeEventListener('pointerup', onUp)
|
|
3066
|
+
}
|
|
3067
|
+
document.addEventListener('pointermove', onMove)
|
|
3068
|
+
document.addEventListener('pointerup', onUp)
|
|
3069
|
+
}
|
|
3070
|
+
|
|
3071
|
+
return (
|
|
3072
|
+
<div
|
|
3073
|
+
className={cn(styles.base, dir.base, disabled && styles.disabled, className)}
|
|
3074
|
+
{...props}
|
|
3075
|
+
>
|
|
3076
|
+
<div
|
|
3077
|
+
ref={trackRef}
|
|
3078
|
+
className={cn(styles.track, dir.track, isH ? s.track : s.vTrack)}
|
|
3079
|
+
onPointerDown={handlePointerDown}
|
|
3080
|
+
>
|
|
3081
|
+
<div
|
|
3082
|
+
className={cn(styles.range, dir.range)}
|
|
3083
|
+
style={isH ? { width: \`\${pct}%\` } : { height: \`\${pct}%\` }}
|
|
3084
|
+
/>
|
|
3085
|
+
<div
|
|
3086
|
+
role="slider"
|
|
3087
|
+
aria-valuenow={current}
|
|
3088
|
+
aria-valuemin={min}
|
|
3089
|
+
aria-valuemax={max}
|
|
3090
|
+
className={cn(styles.thumb, dir.thumb, s.thumb)}
|
|
3091
|
+
style={isH ? { left: \`\${pct}%\` } : { bottom: \`\${pct}%\` }}
|
|
3092
|
+
/>
|
|
3093
|
+
</div>
|
|
3094
|
+
<input
|
|
3095
|
+
ref={ref}
|
|
3096
|
+
type="range"
|
|
3097
|
+
name={name}
|
|
3098
|
+
value={current}
|
|
3099
|
+
min={min}
|
|
3100
|
+
max={max}
|
|
3101
|
+
step={step}
|
|
3102
|
+
className="sr-only"
|
|
3103
|
+
tabIndex={-1}
|
|
3104
|
+
readOnly
|
|
3105
|
+
/>
|
|
3106
|
+
</div>
|
|
3107
|
+
)
|
|
3108
|
+
}
|
|
3109
|
+
)
|
|
3110
|
+
|
|
3111
|
+
Slider.displayName = 'Slider'
|
|
3112
|
+
`;var be=`'use client'
|
|
3113
|
+
|
|
2683
3114
|
import * as React from 'react'
|
|
2684
3115
|
import { cn } from '@/utils/cn'
|
|
2685
3116
|
|
|
@@ -2719,7 +3150,7 @@ export function Switch({
|
|
|
2719
3150
|
</button>
|
|
2720
3151
|
)
|
|
2721
3152
|
}
|
|
2722
|
-
`;var
|
|
3153
|
+
`;var ve=`'use client'
|
|
2723
3154
|
|
|
2724
3155
|
import * as React from 'react'
|
|
2725
3156
|
import { cn } from '@/utils/cn'
|
|
@@ -2833,7 +3264,7 @@ export const Tabs = Object.assign(TabsRoot, {
|
|
|
2833
3264
|
Tab,
|
|
2834
3265
|
Panel
|
|
2835
3266
|
})
|
|
2836
|
-
`;var
|
|
3267
|
+
`;var xe=`import * as React from 'react'
|
|
2837
3268
|
import { cn } from '@/utils/cn'
|
|
2838
3269
|
|
|
2839
3270
|
const styles = {
|
|
@@ -2860,7 +3291,7 @@ export const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(({
|
|
|
2860
3291
|
))
|
|
2861
3292
|
|
|
2862
3293
|
Textarea.displayName = 'Textarea'
|
|
2863
|
-
`;var
|
|
3294
|
+
`;var ye=`'use client'
|
|
2864
3295
|
|
|
2865
3296
|
import * as React from 'react'
|
|
2866
3297
|
import { Toaster as Sonner, toast } from 'sonner'
|
|
@@ -2903,7 +3334,7 @@ function Toaster() {
|
|
|
2903
3334
|
}
|
|
2904
3335
|
|
|
2905
3336
|
export { Toaster, toast }
|
|
2906
|
-
`;var
|
|
3337
|
+
`;var Ne=`import * as React from 'react'
|
|
2907
3338
|
import { cn } from '@/utils/cn'
|
|
2908
3339
|
|
|
2909
3340
|
const styles = {
|
|
@@ -3077,7 +3508,7 @@ export const Table = Object.assign(TableRoot, {
|
|
|
3077
3508
|
Head,
|
|
3078
3509
|
Cell,
|
|
3079
3510
|
})
|
|
3080
|
-
`;var
|
|
3511
|
+
`;var Ce=`import * as React from 'react'
|
|
3081
3512
|
import { cn } from '@/utils/cn'
|
|
3082
3513
|
|
|
3083
3514
|
const styles = {
|
|
@@ -3122,7 +3553,7 @@ export function Tooltip({
|
|
|
3122
3553
|
</span>
|
|
3123
3554
|
)
|
|
3124
3555
|
}
|
|
3125
|
-
`;var
|
|
3556
|
+
`;var Re=`
|
|
3126
3557
|
/* react-day-picker theme integration */
|
|
3127
3558
|
.rdp-root {
|
|
3128
3559
|
--rdp-accent-color: var(--primary);
|
|
@@ -3133,4 +3564,4 @@ export function Tooltip({
|
|
|
3133
3564
|
--rdp-selected-border: none;
|
|
3134
3565
|
--rdp-day_button-border: none;
|
|
3135
3566
|
}
|
|
3136
|
-
`,w=[{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:"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:"dialog",description:"Modal dialog with dot notation, overlay, and escape key",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:"separator",description:"Visual divider with horizontal and vertical orientation",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:[]}],
|
|
3567
|
+
`,w=[{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:"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:"dialog",description:"Modal dialog with dot notation, overlay, and escape key",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:"separator",description:"Visual divider with horizontal and vertical orientation",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:[]}],D={accordion:U,alert:Y,avatar:W,badge:q,breadcrumb:X,button:J,calendar:Q,"date-picker":Z,command:ee,carousel:te,card:ne,checkbox:oe,dialog:re,dropdown:se,input:ae,kbd:ce,label:ie,pagination:le,popover:de,progress:pe,"radio-group":ue,select:me,separator:fe,sidebar:ge,slider:he,switch:be,table:Ne,tabs:ve,textarea:xe,theme:K,toast:ye,tooltip:Ce};async function we(t){let o=process.cwd();e.intro("drivn add");let a=$(o);if(a||(e.log.error("Drivn is not initialized. Run npx drivn@latest create"),e.outro("Cancelled"),process.exit(1)),!t||!t.length){let n=await e.multiselect({message:"Select components to add",options:w.map(r=>({label:r.name,hint:r.description,value:r.name})),required:true});e.isCancel(n)&&(e.cancel("Cancelled"),process.exit(0)),t=n;}let b=t.filter(n=>!w.find(r=>r.name===n));b.length&&(e.log.error(`Unknown components: ${b.join(", ")}`),e.log.info("Available: "+w.map(n=>n.name).join(", ")),e.outro("Cancelled"),process.exit(1));let p=t.includes("theme"),g=t.filter(n=>n!=="theme"),u=new Set,v=new Set,h=n=>{if(u.has(n))return;let r=w.find(c=>c.name===n);r&&(r.dependencies.forEach(c=>h(c)),r.npmDependencies?.forEach(c=>v.add(c)),u.add(n));};g.forEach(h),p&&v.add("next-themes");let x=[...u].filter(n=>!g.includes(n));x.length&&e.log.info(`Required dependency: ${x.join(", ")}`);let l=a.typescript?"tsx":"jsx",N=join(o,a.paths.components);for(let n of u){let r=join(N,`${n}.${l}`);if(m(r)){let C=await e.confirm({message:`${n}.${l} exists. Overwrite?`,initialValue:false});if(e.isCancel(C)||!C){e.log.warn(`Skipped ${n}`);continue}}let c=D[n];c=c.replace(/@\/utils/g,`@/${a.paths.utils.replace(/^src\//,"")}`),d(r,c),e.log.success(`${n} \u2192 ${a.paths.components}/${n}.${l}`);}if(p){let n=join(N,`theme-provider.${l}`);if(m(n)){let c=await e.confirm({message:`theme-provider.${l} exists. Overwrite?`,initialValue:false});!e.isCancel(c)&&c?(d(n,D.theme),e.log.success(`theme-provider \u2192 ${a.paths.components}/theme-provider.${l}`)):e.log.warn("Skipped theme-provider");}else d(n,D.theme),e.log.success(`theme-provider \u2192 ${a.paths.components}/theme-provider.${l}`);if(a.paths.globals){let c=join(o,a.paths.globals);if(m(c)){let C=M(c);C.includes('[data-theme="dark"]')?e.log.warn("Theme tokens already exist in globals \u2014 skipped"):(d(c,C+O),e.log.success(`Theme tokens appended to ${i.cyan(a.paths.globals)}`));}else e.log.warn(`Globals file not found at ${a.paths.globals}`);}else e.log.warn('No globals path in drivn.config.json. Add "globals" to paths');let r=a.paths.components.replace(/^src\//,"@/");e.log.message(""),e.log.info(i.bold("Complete the setup:")),e.log.message(""),e.log.message(i.bold(`${i.cyan("1.")} Import ThemeProvider in your root layout:`)),e.log.message(i.cyan(` import { ThemeProvider } from "${r}/theme-provider"`)),e.log.message(""),e.log.message(i.bold(`${i.cyan("2.")} Add suppressHydrationWarning to <html>:`)),e.log.message(i.cyan(" <html suppressHydrationWarning>")),e.log.message(""),e.log.message(i.bold(`${i.cyan("3.")} Wrap your app with ThemeProvider:`)),e.log.message(i.cyan(" <ThemeProvider>")),e.log.message(i.cyan(" {children}")),e.log.message(i.cyan(" </ThemeProvider>")),e.log.message("");}if(u.has("calendar")&&a.paths.globals){let n=join(o,a.paths.globals);if(m(n)){let r=M(n);r.includes(".rdp-root")?e.log.warn("Calendar tokens already exist in globals \u2014 skipped"):(d(n,r+Re),e.log.success(`Calendar tokens appended to ${i.cyan(a.paths.globals)}`));}}if(v.size){let n=P(o),r=[...v],c=e.spinner();c.start("Installing packages");try{execSync(y(n,r),{cwd:o,stdio:"ignore"}),c.stop("Packages installed");}catch{c.stop("Failed to install packages"),e.log.warn(`Run manually: ${y(n,r)}`);}}e.outro("Done.");}var ke={version:"1.5.1"};var T=new Command;T.name("drivn").description("Drivn \u2014 Modern UI components").version(ke.version);T.command("create").description("Initialize Drivn in your project").action(G);T.command("add [components...]").description("Add components to your project").action(we);T.parse();
|