drivn 1.0.2 → 1.1.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.
- package/dist/index.js +192 -266
- 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
|
|
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 M={next:"Next.js",react:"React"};function B(t){let n=join(t,"package.json");if(!existsSync(n))throw new Error("package.json not found");let c=JSON.parse(readFileSync(n,"utf-8")),v={...c.dependencies,...c.devDependencies},d="react";v.next&&(d="next");let m=existsSync(join(t,"src")),f=existsSync(join(t,"tsconfig.json"));return {framework:d,srcDir:m,typescript:f}}var H="drivn.config.json";function V(t){let n=join(t,H);return existsSync(n)?JSON.parse(readFileSync(n,"utf-8")):null}function z(t,n){let c=join(t,H);writeFileSync(c,JSON.stringify(n,null,2));}function he(t){existsSync(t)||mkdirSync(t,{recursive:true});}function p(t,n){he(dirname(t)),writeFileSync(t,n);}function F(t){return readFileSync(t,"utf-8")}function h(t){return existsSync(t)}function k(t){return existsSync(join(t,"pnpm-lock.yaml"))?"pnpm":"npm"}function y(t,n){let c=n.join(" ");return t==="pnpm"?`pnpm add ${c}`:`npm install ${c}`}function _(t){return t==="pnpm"?"pnpm dlx":"npx"}var T=`@import "tailwindcss";
|
|
3
3
|
|
|
4
4
|
:root {
|
|
5
5
|
/* Surfaces */
|
|
@@ -70,7 +70,7 @@ body {
|
|
|
70
70
|
color: var(--color-foreground);
|
|
71
71
|
font-family: system-ui, -apple-system, sans-serif;
|
|
72
72
|
}
|
|
73
|
-
`,
|
|
73
|
+
`,L=`
|
|
74
74
|
/* Drivn Dark/Light Theme */
|
|
75
75
|
:root,
|
|
76
76
|
[data-theme="dark"] {
|
|
@@ -142,7 +142,7 @@ import { twMerge } from 'tailwind-merge'
|
|
|
142
142
|
export function cn(...inputs: ClassValue[]) {
|
|
143
143
|
return twMerge(clsx(inputs))
|
|
144
144
|
}
|
|
145
|
-
`,Ne=["src/app/globals.css","src/styles/globals.css","src/styles/globals.scss","app/globals.css"];function we(t){for(let n of Ne)if(h(join(t,n)))return n;return null}async function U(){let t=process.cwd();console.log(""),console.log(i.bgCyan(i.bold(i.black(" Drivn "))));let n;try{n=
|
|
145
|
+
`,Ne=["src/app/globals.css","src/styles/globals.css","src/styles/globals.scss","app/globals.css"];function we(t){for(let n of Ne)if(h(join(t,n)))return n;return null}async function U(){let t=process.cwd();console.log(""),console.log(i.bgCyan(i.bold(i.black(" Drivn "))));let n;try{n=B(t),e.log.success(`Detected ${i.cyan(M[n.framework])}`);}catch{e.log.error("No package.json found. Run this command in a project directory."),e.outro("Setup cancelled"),process.exit(1);}if(h(join(t,"drivn.config.json"))){let s=await e.confirm({message:"Config already exists. Overwrite?",initialValue:false});(e.isCancel(s)||!s)&&(e.cancel("Setup cancelled"),process.exit(0));}let c=n.srcDir?"src/components/ui":"components/ui",v=n.srcDir?"src/utils":"utils",d=await e.group({components:()=>e.text({message:"Where should components be installed?",placeholder:c,defaultValue:c}),utils:()=>e.text({message:"Where should utilities be placed?",placeholder:v,defaultValue:v})},{onCancel:()=>{e.cancel("Setup cancelled"),process.exit(0);}}),m={framework:n.framework,typescript:n.typescript,paths:{components:d.components,utils:d.utils},installed:[]},f=n.typescript?"ts":"js",b=join(t,d.utils,`cn.${f}`);h(b)||p(b,ye);let g=we(t);if(g){let s=await e.confirm({message:`Found ${i.cyan(g)}. Add Drivn color tokens?`,initialValue:true});!e.isCancel(s)&&s&&(p(join(t,g),T),m.paths.globals=g,e.log.success(`Color tokens written to ${i.cyan(g)}`));}else {let s=n.srcDir?"src/styles/globals.css":"styles/globals.css",a=await e.text({message:"Where should the globals CSS file be created?",placeholder:s,defaultValue:s});e.isCancel(a)||(p(join(t,a),T),m.paths.globals=a,e.log.success(`Color tokens written to ${i.cyan(a)}`));}z(t,m);let x=k(t),l=_(x),N=["clsx","tailwind-merge","lucide-react"],o=e.spinner();o.start("Installing dependencies");try{execSync(y(x,N),{cwd:t,stdio:"ignore"}),o.stop("Dependencies installed");}catch{o.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 G=`'use client'
|
|
146
146
|
|
|
147
147
|
import { ThemeProvider as NextThemesProvider } from 'next-themes'
|
|
148
148
|
|
|
@@ -183,47 +183,32 @@ const styles = {
|
|
|
183
183
|
}
|
|
184
184
|
|
|
185
185
|
interface AccordionCtx {
|
|
186
|
-
|
|
187
|
-
toggle: (
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
const Ctx = React.createContext<AccordionCtx | null>(null)
|
|
191
|
-
const ItemCtx = React.createContext<string | null>(null)
|
|
192
|
-
|
|
193
|
-
function useAccordion() {
|
|
194
|
-
const ctx = React.useContext(Ctx)
|
|
195
|
-
if (!ctx) throw new Error('Accordion compound used outside <Accordion>')
|
|
196
|
-
return ctx
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
function useItemValue() {
|
|
200
|
-
const value = React.useContext(ItemCtx)
|
|
201
|
-
if (!value) throw new Error(
|
|
202
|
-
'Accordion sub-component used outside <Accordion.Item>'
|
|
203
|
-
)
|
|
204
|
-
return value
|
|
186
|
+
open: Set<string>
|
|
187
|
+
toggle: (v: string) => void
|
|
205
188
|
}
|
|
206
189
|
|
|
207
190
|
function AccordionRoot({
|
|
208
191
|
children,
|
|
209
192
|
defaultValue,
|
|
193
|
+
multiple,
|
|
210
194
|
className,
|
|
211
195
|
}: {
|
|
212
196
|
children: React.ReactNode
|
|
213
|
-
defaultValue?: string
|
|
197
|
+
defaultValue?: string | string[]
|
|
198
|
+
multiple?: boolean
|
|
214
199
|
className?: string
|
|
215
200
|
}) {
|
|
216
|
-
const [
|
|
217
|
-
|
|
218
|
-
)
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
201
|
+
const [open, setOpen] = React.useState(() => new Set([defaultValue ?? []].flat()))
|
|
202
|
+
|
|
203
|
+
const toggle = (v: string) =>
|
|
204
|
+
setOpen((prev) => {
|
|
205
|
+
const next = new Set(multiple ? prev : [])
|
|
206
|
+
prev.has(v) ? next.delete(v) : next.add(v)
|
|
207
|
+
return next
|
|
208
|
+
})
|
|
224
209
|
|
|
225
210
|
return (
|
|
226
|
-
<Ctx.Provider value={{
|
|
211
|
+
<Ctx.Provider value={{ open, toggle }}>
|
|
227
212
|
<div className={cn(styles.base, className)}>
|
|
228
213
|
{children}
|
|
229
214
|
</div>
|
|
@@ -250,17 +235,20 @@ function Item({
|
|
|
250
235
|
function Trigger({
|
|
251
236
|
children,
|
|
252
237
|
className,
|
|
238
|
+
...props
|
|
253
239
|
}: {
|
|
254
240
|
children: React.ReactNode
|
|
255
241
|
className?: string
|
|
256
|
-
}) {
|
|
257
|
-
const {
|
|
258
|
-
const value =
|
|
259
|
-
const isOpen =
|
|
242
|
+
} & React.ButtonHTMLAttributes<HTMLButtonElement>) {
|
|
243
|
+
const { open, toggle } = useCtx()
|
|
244
|
+
const value = React.useContext(ItemCtx)
|
|
245
|
+
const isOpen = open.has(value)
|
|
260
246
|
return (
|
|
261
247
|
<button
|
|
248
|
+
aria-expanded={isOpen}
|
|
262
249
|
className={cn(styles.trigger, className)}
|
|
263
250
|
onClick={() => toggle(value)}
|
|
251
|
+
{...props}
|
|
264
252
|
>
|
|
265
253
|
{children}
|
|
266
254
|
<ChevronDown className={cn(styles.icon, isOpen && 'rotate-180')} />
|
|
@@ -275,11 +263,12 @@ function Content({
|
|
|
275
263
|
children: React.ReactNode
|
|
276
264
|
className?: string
|
|
277
265
|
}) {
|
|
278
|
-
const {
|
|
279
|
-
const value =
|
|
280
|
-
const isOpen =
|
|
266
|
+
const { open } = useCtx()
|
|
267
|
+
const value = React.useContext(ItemCtx)
|
|
268
|
+
const isOpen = open.has(value)
|
|
281
269
|
return (
|
|
282
270
|
<div
|
|
271
|
+
role="region"
|
|
283
272
|
className={styles.panel}
|
|
284
273
|
style={{ gridTemplateRows: isOpen ? '1fr' : '0fr' }}
|
|
285
274
|
>
|
|
@@ -290,12 +279,19 @@ function Content({
|
|
|
290
279
|
)
|
|
291
280
|
}
|
|
292
281
|
|
|
282
|
+
const Ctx = React.createContext<AccordionCtx | null>(null)
|
|
283
|
+
const ItemCtx = React.createContext('')
|
|
284
|
+
|
|
285
|
+
function useCtx() {
|
|
286
|
+
const c = React.useContext(Ctx)
|
|
287
|
+
if (!c) throw new Error('Accordion compound used outside <Accordion>')
|
|
288
|
+
return c
|
|
289
|
+
}
|
|
290
|
+
|
|
293
291
|
export const Accordion = Object.assign(AccordionRoot, {
|
|
294
|
-
Item,
|
|
295
|
-
Trigger,
|
|
296
|
-
Content,
|
|
292
|
+
Item, Trigger, Content,
|
|
297
293
|
})
|
|
298
|
-
`;var
|
|
294
|
+
`;var X=`import * as React from 'react'
|
|
299
295
|
import { cn } from '@/utils/cn'
|
|
300
296
|
|
|
301
297
|
const styles = {
|
|
@@ -310,9 +306,7 @@ const styles = {
|
|
|
310
306
|
description: 'text-sm opacity-90',
|
|
311
307
|
}
|
|
312
308
|
|
|
313
|
-
type IconProp =
|
|
314
|
-
| React.ComponentType<{ className?: string }>
|
|
315
|
-
| React.ReactElement
|
|
309
|
+
type IconProp = React.ComponentType<{ className?: string }> | React.ReactElement
|
|
316
310
|
|
|
317
311
|
interface AlertProps {
|
|
318
312
|
variant?: keyof typeof styles.variants
|
|
@@ -345,7 +339,7 @@ export function Alert({
|
|
|
345
339
|
</div>
|
|
346
340
|
)
|
|
347
341
|
}
|
|
348
|
-
`;var
|
|
342
|
+
`;var q=`import * as React from 'react'
|
|
349
343
|
import { cn } from '@/utils/cn'
|
|
350
344
|
|
|
351
345
|
const styles = {
|
|
@@ -419,7 +413,7 @@ export function Badge({ variant = 'default', className, children }: BadgeProps)
|
|
|
419
413
|
</span>
|
|
420
414
|
)
|
|
421
415
|
}
|
|
422
|
-
`;var
|
|
416
|
+
`;var K=`import * as React from 'react'
|
|
423
417
|
import { Loader2 } from 'lucide-react'
|
|
424
418
|
import { cn } from '@/utils/cn'
|
|
425
419
|
|
|
@@ -450,9 +444,7 @@ const styles = {
|
|
|
450
444
|
},
|
|
451
445
|
}
|
|
452
446
|
|
|
453
|
-
type IconProp =
|
|
454
|
-
| React.ComponentType<{ className?: string }>
|
|
455
|
-
| React.ReactElement
|
|
447
|
+
type IconProp = React.ComponentType<{ className?: string }> | React.ReactElement
|
|
456
448
|
|
|
457
449
|
interface ButtonProps
|
|
458
450
|
extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
@@ -464,33 +456,22 @@ interface ButtonProps
|
|
|
464
456
|
rightIcon?: IconProp
|
|
465
457
|
}
|
|
466
458
|
|
|
467
|
-
export const Button = React.forwardRef<
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
children,
|
|
480
|
-
...props
|
|
481
|
-
},
|
|
482
|
-
ref
|
|
483
|
-
) => (
|
|
459
|
+
export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(({
|
|
460
|
+
className,
|
|
461
|
+
variant = 'default',
|
|
462
|
+
size = 'md',
|
|
463
|
+
rounded = 'full',
|
|
464
|
+
loading,
|
|
465
|
+
disabled,
|
|
466
|
+
leftIcon: LeftIcon,
|
|
467
|
+
rightIcon: RightIcon,
|
|
468
|
+
children,
|
|
469
|
+
...props
|
|
470
|
+
}, ref) => (
|
|
484
471
|
<button
|
|
485
472
|
ref={ref}
|
|
486
473
|
disabled={loading || disabled}
|
|
487
|
-
className={cn(
|
|
488
|
-
styles.base,
|
|
489
|
-
styles.sizes[size],
|
|
490
|
-
styles.variants[variant],
|
|
491
|
-
styles.rounded[rounded],
|
|
492
|
-
className
|
|
493
|
-
)}
|
|
474
|
+
className={cn(styles.base, styles.sizes[size], styles.variants[variant], styles.rounded[rounded], className)}
|
|
494
475
|
{...props}
|
|
495
476
|
>
|
|
496
477
|
{loading && (
|
|
@@ -596,42 +577,25 @@ const styles = {
|
|
|
596
577
|
label: 'text-sm text-foreground select-none',
|
|
597
578
|
}
|
|
598
579
|
|
|
599
|
-
interface CheckboxProps
|
|
600
|
-
extends Omit<
|
|
601
|
-
React.InputHTMLAttributes<HTMLInputElement>,
|
|
602
|
-
'type'
|
|
603
|
-
> {
|
|
580
|
+
interface CheckboxProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'type'> {
|
|
604
581
|
label?: string
|
|
605
582
|
}
|
|
606
583
|
|
|
607
|
-
export const Checkbox = React.forwardRef<
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
...props
|
|
618
|
-
},
|
|
619
|
-
ref
|
|
620
|
-
) => {
|
|
621
|
-
const [internal, setInternal] = React.useState(
|
|
622
|
-
defaultChecked ?? false
|
|
623
|
-
)
|
|
584
|
+
export const Checkbox = React.forwardRef<HTMLInputElement, CheckboxProps>(({
|
|
585
|
+
className,
|
|
586
|
+
label,
|
|
587
|
+
checked,
|
|
588
|
+
defaultChecked,
|
|
589
|
+
onChange,
|
|
590
|
+
disabled,
|
|
591
|
+
...props
|
|
592
|
+
}, ref) => {
|
|
593
|
+
const [internal, setInternal] = React.useState(defaultChecked ?? false)
|
|
624
594
|
const isControlled = checked !== undefined
|
|
625
595
|
const isChecked = isControlled ? checked : internal
|
|
626
596
|
|
|
627
597
|
return (
|
|
628
|
-
<label
|
|
629
|
-
className={cn(
|
|
630
|
-
styles.base,
|
|
631
|
-
disabled && 'opacity-50 cursor-default',
|
|
632
|
-
className
|
|
633
|
-
)}
|
|
634
|
-
>
|
|
598
|
+
<label className={cn(styles.base, disabled && 'opacity-50 cursor-default', className)}>
|
|
635
599
|
<input
|
|
636
600
|
ref={ref}
|
|
637
601
|
type="checkbox"
|
|
@@ -645,12 +609,7 @@ export const Checkbox = React.forwardRef<
|
|
|
645
609
|
}}
|
|
646
610
|
{...props}
|
|
647
611
|
/>
|
|
648
|
-
<span
|
|
649
|
-
className={cn(
|
|
650
|
-
styles.box,
|
|
651
|
-
isChecked && styles.checked
|
|
652
|
-
)}
|
|
653
|
-
>
|
|
612
|
+
<span className={cn(styles.box, isChecked && styles.checked)}>
|
|
654
613
|
{isChecked && (
|
|
655
614
|
<Check className="w-2.5 h-2.5 text-primary-foreground" />
|
|
656
615
|
)}
|
|
@@ -672,23 +631,24 @@ import { cn } from '@/utils/cn'
|
|
|
672
631
|
import { Button } from '@/components/ui/button'
|
|
673
632
|
|
|
674
633
|
const styles = {
|
|
675
|
-
|
|
676
|
-
'fixed inset-0
|
|
677
|
-
'
|
|
678
|
-
'
|
|
634
|
+
base: cn(
|
|
635
|
+
'fixed inset-0 m-0 p-0 border-none',
|
|
636
|
+
'max-w-none max-h-none w-screen h-dvh',
|
|
637
|
+
'flex items-center justify-center bg-overlay',
|
|
638
|
+
'backdrop-blur-sm transition-opacity duration-150',
|
|
639
|
+
'ease-out'
|
|
679
640
|
),
|
|
680
641
|
content: cn(
|
|
681
|
-
'relative w-full max-w-md mx-4 p-6',
|
|
642
|
+
'relative w-full max-w-md mx-4 p-6 shadow-xl',
|
|
682
643
|
'bg-card border border-border rounded-[20px]',
|
|
683
|
-
'shadow-xl',
|
|
684
644
|
'transition-[scale] duration-150 ease-out'
|
|
685
645
|
),
|
|
686
646
|
title: 'text-lg font-semibold text-foreground mb-4',
|
|
687
647
|
close: cn(
|
|
688
|
-
'absolute top-4 right-4 w-8 h-8',
|
|
648
|
+
'absolute top-4 right-4 w-8 h-8 cursor-pointer',
|
|
689
649
|
'flex items-center justify-center rounded-full',
|
|
690
650
|
'text-muted-foreground hover:text-foreground',
|
|
691
|
-
'hover:bg-accent transition-colors
|
|
651
|
+
'hover:bg-accent transition-colors'
|
|
692
652
|
),
|
|
693
653
|
}
|
|
694
654
|
|
|
@@ -697,14 +657,6 @@ interface DialogCtx {
|
|
|
697
657
|
setOpen: (v: boolean) => void
|
|
698
658
|
}
|
|
699
659
|
|
|
700
|
-
const Ctx = React.createContext<DialogCtx | null>(null)
|
|
701
|
-
|
|
702
|
-
function useDialog() {
|
|
703
|
-
const ctx = React.useContext(Ctx)
|
|
704
|
-
if (!ctx) throw new Error('Dialog compound used outside <Dialog>')
|
|
705
|
-
return ctx
|
|
706
|
-
}
|
|
707
|
-
|
|
708
660
|
function DialogRoot({
|
|
709
661
|
children,
|
|
710
662
|
open: controlled,
|
|
@@ -716,15 +668,16 @@ function DialogRoot({
|
|
|
716
668
|
}) {
|
|
717
669
|
const [uncontrolled, setUncontrolled] = React.useState(false)
|
|
718
670
|
const open = controlled ?? uncontrolled
|
|
719
|
-
const setOpen =
|
|
720
|
-
(v
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
},
|
|
724
|
-
[controlled, onOpenChange]
|
|
725
|
-
)
|
|
671
|
+
const setOpen = (v: boolean) => {
|
|
672
|
+
onOpenChange?.(v)
|
|
673
|
+
if (controlled === undefined) setUncontrolled(v)
|
|
674
|
+
}
|
|
726
675
|
|
|
727
|
-
return
|
|
676
|
+
return (
|
|
677
|
+
<Ctx.Provider value={{ open, setOpen }}>
|
|
678
|
+
{children}
|
|
679
|
+
</Ctx.Provider>
|
|
680
|
+
)
|
|
728
681
|
}
|
|
729
682
|
|
|
730
683
|
function Trigger({
|
|
@@ -756,43 +709,51 @@ function Content({
|
|
|
756
709
|
className?: string
|
|
757
710
|
}) {
|
|
758
711
|
const { open, setOpen } = useDialog()
|
|
712
|
+
const ref = React.useRef<HTMLDialogElement>(null)
|
|
713
|
+
const [visible, setVisible] = React.useState(false)
|
|
759
714
|
|
|
760
715
|
React.useEffect(() => {
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
716
|
+
const el = ref.current
|
|
717
|
+
if (!el) return
|
|
718
|
+
const onCancel = (e: Event) => {
|
|
719
|
+
e.preventDefault()
|
|
720
|
+
setOpen(false)
|
|
764
721
|
}
|
|
765
|
-
|
|
766
|
-
|
|
722
|
+
el.addEventListener('cancel', onCancel)
|
|
723
|
+
if (open) {
|
|
724
|
+
if (!el.open) el.showModal()
|
|
725
|
+
document.body.style.overflow = 'hidden'
|
|
726
|
+
requestAnimationFrame(() => setVisible(true))
|
|
727
|
+
return () => {
|
|
728
|
+
el.removeEventListener('cancel', onCancel)
|
|
729
|
+
document.body.style.overflow = ''
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
setVisible(false)
|
|
733
|
+
const id = setTimeout(() => {
|
|
734
|
+
if (el.open) el.close()
|
|
735
|
+
}, 150)
|
|
767
736
|
return () => {
|
|
768
|
-
|
|
769
|
-
|
|
737
|
+
el.removeEventListener('cancel', onCancel)
|
|
738
|
+
clearTimeout(id)
|
|
770
739
|
}
|
|
771
740
|
}, [open, setOpen])
|
|
772
741
|
|
|
773
742
|
return (
|
|
774
|
-
<
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
open
|
|
778
|
-
? 'opacity-100'
|
|
779
|
-
: 'opacity-0 pointer-events-none'
|
|
780
|
-
)}
|
|
743
|
+
<dialog
|
|
744
|
+
ref={ref}
|
|
745
|
+
className={cn(styles.base, visible ? 'opacity-100' : 'opacity-0 pointer-events-none')}
|
|
781
746
|
onClick={(e) => {
|
|
782
747
|
if (e.target === e.currentTarget) setOpen(false)
|
|
783
748
|
}}
|
|
784
749
|
>
|
|
785
|
-
<div
|
|
786
|
-
|
|
787
|
-
styles.
|
|
788
|
-
open ? 'scale-100' : 'scale-95',
|
|
789
|
-
className
|
|
750
|
+
<div className={cn(styles.content, visible ? 'scale-100' : 'scale-95', className)}>
|
|
751
|
+
{title && (
|
|
752
|
+
<h2 className={styles.title}>{title}</h2>
|
|
790
753
|
)}
|
|
791
|
-
>
|
|
792
|
-
{title && <h2 className={styles.title}>{title}</h2>}
|
|
793
754
|
{children}
|
|
794
755
|
</div>
|
|
795
|
-
</
|
|
756
|
+
</dialog>
|
|
796
757
|
)
|
|
797
758
|
}
|
|
798
759
|
|
|
@@ -808,6 +769,14 @@ function Close({ className }: { className?: string }) {
|
|
|
808
769
|
)
|
|
809
770
|
}
|
|
810
771
|
|
|
772
|
+
const Ctx = React.createContext<DialogCtx | null>(null)
|
|
773
|
+
|
|
774
|
+
function useDialog() {
|
|
775
|
+
const ctx = React.useContext(Ctx)
|
|
776
|
+
if (!ctx) throw new Error('Dialog compound used outside <Dialog>')
|
|
777
|
+
return ctx
|
|
778
|
+
}
|
|
779
|
+
|
|
811
780
|
export const Dialog = Object.assign(DialogRoot, {
|
|
812
781
|
Trigger,
|
|
813
782
|
Content,
|
|
@@ -851,15 +820,7 @@ interface DropdownCtx {
|
|
|
851
820
|
align: keyof typeof styles.align
|
|
852
821
|
}
|
|
853
822
|
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
function useDropdown() {
|
|
857
|
-
const ctx = React.useContext(Ctx)
|
|
858
|
-
if (!ctx) throw new Error(
|
|
859
|
-
'Dropdown compound used outside <Dropdown>'
|
|
860
|
-
)
|
|
861
|
-
return ctx
|
|
862
|
-
}
|
|
823
|
+
type IconProp = React.ComponentType<{ className?: string }> | React.ReactElement
|
|
863
824
|
|
|
864
825
|
function DropdownRoot({
|
|
865
826
|
children,
|
|
@@ -925,50 +886,35 @@ function Content({
|
|
|
925
886
|
}) {
|
|
926
887
|
const { open, align } = useDropdown()
|
|
927
888
|
return (
|
|
928
|
-
<div
|
|
929
|
-
className={cn(
|
|
930
|
-
styles.content,
|
|
931
|
-
styles.align[align],
|
|
932
|
-
open
|
|
933
|
-
? 'opacity-100 scale-100'
|
|
934
|
-
: 'opacity-0 scale-95 pointer-events-none',
|
|
935
|
-
className
|
|
936
|
-
)}
|
|
937
|
-
>
|
|
889
|
+
<div className={cn(styles.content, styles.align[align], open ? 'opacity-100 scale-100' : 'opacity-0 scale-95 pointer-events-none', className)}>
|
|
938
890
|
{children}
|
|
939
891
|
</div>
|
|
940
892
|
)
|
|
941
893
|
}
|
|
942
894
|
|
|
943
|
-
type IconProp =
|
|
944
|
-
| React.ComponentType<{ className?: string }>
|
|
945
|
-
| React.ReactElement
|
|
946
|
-
|
|
947
895
|
function Item({
|
|
948
896
|
children,
|
|
949
897
|
onClick,
|
|
950
898
|
icon: Icon,
|
|
951
899
|
destructive,
|
|
952
900
|
className,
|
|
901
|
+
...props
|
|
953
902
|
}: {
|
|
954
903
|
children: React.ReactNode
|
|
955
904
|
onClick?: () => void
|
|
956
905
|
icon?: IconProp
|
|
957
906
|
destructive?: boolean
|
|
958
907
|
className?: string
|
|
959
|
-
}) {
|
|
908
|
+
} & Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'onClick'>) {
|
|
960
909
|
const { setOpen } = useDropdown()
|
|
961
910
|
return (
|
|
962
911
|
<button
|
|
963
|
-
className={cn(
|
|
964
|
-
styles.item,
|
|
965
|
-
destructive && styles.destructive,
|
|
966
|
-
className
|
|
967
|
-
)}
|
|
912
|
+
className={cn(styles.item, destructive && styles.destructive, className)}
|
|
968
913
|
onClick={() => {
|
|
969
914
|
onClick?.()
|
|
970
915
|
setOpen(false)
|
|
971
916
|
}}
|
|
917
|
+
{...props}
|
|
972
918
|
>
|
|
973
919
|
{Icon && (
|
|
974
920
|
React.isValidElement(Icon)
|
|
@@ -1018,6 +964,14 @@ function DropdownSeparator({
|
|
|
1018
964
|
)
|
|
1019
965
|
}
|
|
1020
966
|
|
|
967
|
+
const Ctx = React.createContext<DropdownCtx | null>(null)
|
|
968
|
+
|
|
969
|
+
function useDropdown() {
|
|
970
|
+
const ctx = React.useContext(Ctx)
|
|
971
|
+
if (!ctx) throw new Error('Dropdown compound used outside <Dropdown>')
|
|
972
|
+
return ctx
|
|
973
|
+
}
|
|
974
|
+
|
|
1021
975
|
export const Dropdown = Object.assign(DropdownRoot, {
|
|
1022
976
|
Trigger,
|
|
1023
977
|
Content,
|
|
@@ -1040,8 +994,10 @@ const styles = {
|
|
|
1040
994
|
|
|
1041
995
|
type InputProps = React.InputHTMLAttributes<HTMLInputElement>
|
|
1042
996
|
|
|
1043
|
-
export const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|
1044
|
-
|
|
997
|
+
export const Input = React.forwardRef<HTMLInputElement, InputProps>(({
|
|
998
|
+
className,
|
|
999
|
+
...props
|
|
1000
|
+
}, ref) => (
|
|
1045
1001
|
<input ref={ref} className={cn(styles.base, className)} {...props} />
|
|
1046
1002
|
)
|
|
1047
1003
|
)
|
|
@@ -1075,14 +1031,6 @@ interface PopoverCtx {
|
|
|
1075
1031
|
position: keyof typeof styles.positions
|
|
1076
1032
|
}
|
|
1077
1033
|
|
|
1078
|
-
const Ctx = React.createContext<PopoverCtx | null>(null)
|
|
1079
|
-
|
|
1080
|
-
function usePopover() {
|
|
1081
|
-
const ctx = React.useContext(Ctx)
|
|
1082
|
-
if (!ctx) throw new Error('Popover compound used outside <Popover>')
|
|
1083
|
-
return ctx
|
|
1084
|
-
}
|
|
1085
|
-
|
|
1086
1034
|
function PopoverRoot({
|
|
1087
1035
|
children,
|
|
1088
1036
|
position = 'bottom',
|
|
@@ -1142,21 +1090,20 @@ function Content({
|
|
|
1142
1090
|
}) {
|
|
1143
1091
|
const { open, position } = usePopover()
|
|
1144
1092
|
return (
|
|
1145
|
-
<div
|
|
1146
|
-
className={cn(
|
|
1147
|
-
styles.content,
|
|
1148
|
-
styles.positions[position],
|
|
1149
|
-
open
|
|
1150
|
-
? 'opacity-100 scale-100'
|
|
1151
|
-
: 'opacity-0 scale-95 pointer-events-none',
|
|
1152
|
-
className
|
|
1153
|
-
)}
|
|
1154
|
-
>
|
|
1093
|
+
<div className={cn(styles.content, styles.positions[position], open ? 'opacity-100 scale-100' : 'opacity-0 scale-95 pointer-events-none', className)}>
|
|
1155
1094
|
{children}
|
|
1156
1095
|
</div>
|
|
1157
1096
|
)
|
|
1158
1097
|
}
|
|
1159
1098
|
|
|
1099
|
+
const Ctx = React.createContext<PopoverCtx | null>(null)
|
|
1100
|
+
|
|
1101
|
+
function usePopover() {
|
|
1102
|
+
const ctx = React.useContext(Ctx)
|
|
1103
|
+
if (!ctx) throw new Error('Popover compound used outside <Popover>')
|
|
1104
|
+
return ctx
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1160
1107
|
export const Popover = Object.assign(PopoverRoot, {
|
|
1161
1108
|
Trigger,
|
|
1162
1109
|
Content,
|
|
@@ -1238,14 +1185,6 @@ interface SelectCtx {
|
|
|
1238
1185
|
onSelect: (v: string) => void
|
|
1239
1186
|
}
|
|
1240
1187
|
|
|
1241
|
-
const Ctx = React.createContext<SelectCtx | null>(null)
|
|
1242
|
-
|
|
1243
|
-
function useSelect() {
|
|
1244
|
-
const ctx = React.useContext(Ctx)
|
|
1245
|
-
if (!ctx) throw new Error('Select compound used outside <Select>')
|
|
1246
|
-
return ctx
|
|
1247
|
-
}
|
|
1248
|
-
|
|
1249
1188
|
function SelectRoot({
|
|
1250
1189
|
children,
|
|
1251
1190
|
value,
|
|
@@ -1290,16 +1229,18 @@ function Trigger({
|
|
|
1290
1229
|
placeholder = 'Select...',
|
|
1291
1230
|
children,
|
|
1292
1231
|
className,
|
|
1232
|
+
...props
|
|
1293
1233
|
}: {
|
|
1294
1234
|
placeholder?: string
|
|
1295
1235
|
children?: React.ReactNode
|
|
1296
1236
|
className?: string
|
|
1297
|
-
}) {
|
|
1237
|
+
} & Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'onClick'>) {
|
|
1298
1238
|
const { open, setOpen } = useSelect()
|
|
1299
1239
|
return (
|
|
1300
1240
|
<button
|
|
1301
1241
|
className={cn(styles.trigger, className)}
|
|
1302
1242
|
onClick={() => setOpen(!open)}
|
|
1243
|
+
{...props}
|
|
1303
1244
|
>
|
|
1304
1245
|
<span className={!children ? styles.placeholder : undefined}>
|
|
1305
1246
|
{children ?? placeholder}
|
|
@@ -1318,15 +1259,7 @@ function Menu({
|
|
|
1318
1259
|
}) {
|
|
1319
1260
|
const { open } = useSelect()
|
|
1320
1261
|
return (
|
|
1321
|
-
<div
|
|
1322
|
-
className={cn(
|
|
1323
|
-
styles.menu,
|
|
1324
|
-
open
|
|
1325
|
-
? 'opacity-100 scale-100'
|
|
1326
|
-
: 'opacity-0 scale-95 pointer-events-none',
|
|
1327
|
-
className
|
|
1328
|
-
)}
|
|
1329
|
-
>
|
|
1262
|
+
<div className={cn(styles.menu, open ? 'opacity-100 scale-100' : 'opacity-0 scale-95 pointer-events-none', className)}>
|
|
1330
1263
|
{children}
|
|
1331
1264
|
</div>
|
|
1332
1265
|
)
|
|
@@ -1336,26 +1269,32 @@ function Option({
|
|
|
1336
1269
|
value: optValue,
|
|
1337
1270
|
children,
|
|
1338
1271
|
className,
|
|
1272
|
+
...props
|
|
1339
1273
|
}: {
|
|
1340
1274
|
value: string
|
|
1341
1275
|
children: React.ReactNode
|
|
1342
1276
|
className?: string
|
|
1343
|
-
}) {
|
|
1277
|
+
} & Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'onClick'>) {
|
|
1344
1278
|
const { value, onSelect } = useSelect()
|
|
1345
1279
|
return (
|
|
1346
1280
|
<button
|
|
1347
|
-
className={cn(
|
|
1348
|
-
styles.option,
|
|
1349
|
-
optValue === value && styles.selected,
|
|
1350
|
-
className
|
|
1351
|
-
)}
|
|
1281
|
+
className={cn(styles.option, optValue === value && styles.selected, className)}
|
|
1352
1282
|
onClick={() => onSelect(optValue)}
|
|
1283
|
+
{...props}
|
|
1353
1284
|
>
|
|
1354
1285
|
{children}
|
|
1355
1286
|
</button>
|
|
1356
1287
|
)
|
|
1357
1288
|
}
|
|
1358
1289
|
|
|
1290
|
+
const Ctx = React.createContext<SelectCtx | null>(null)
|
|
1291
|
+
|
|
1292
|
+
function useSelect() {
|
|
1293
|
+
const ctx = React.useContext(Ctx)
|
|
1294
|
+
if (!ctx) throw new Error('Select compound used outside <Select>')
|
|
1295
|
+
return ctx
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1359
1298
|
export const Select = Object.assign(SelectRoot, {
|
|
1360
1299
|
Trigger,
|
|
1361
1300
|
Menu,
|
|
@@ -1402,36 +1341,27 @@ const styles = {
|
|
|
1402
1341
|
),
|
|
1403
1342
|
}
|
|
1404
1343
|
|
|
1405
|
-
interface SwitchProps
|
|
1344
|
+
interface SwitchProps
|
|
1345
|
+
extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'onChange'> {
|
|
1406
1346
|
checked?: boolean
|
|
1407
1347
|
onChange?: (checked: boolean) => void
|
|
1408
|
-
className?: string
|
|
1409
1348
|
}
|
|
1410
1349
|
|
|
1411
1350
|
export function Switch({
|
|
1412
1351
|
checked = false,
|
|
1413
1352
|
onChange,
|
|
1414
1353
|
className,
|
|
1354
|
+
...props
|
|
1415
1355
|
}: SwitchProps) {
|
|
1416
1356
|
return (
|
|
1417
1357
|
<button
|
|
1418
1358
|
role="switch"
|
|
1419
1359
|
aria-checked={checked}
|
|
1420
1360
|
onClick={() => onChange?.(!checked)}
|
|
1421
|
-
className={cn(
|
|
1422
|
-
|
|
1423
|
-
checked ? 'bg-primary' : 'bg-border',
|
|
1424
|
-
className
|
|
1425
|
-
)}
|
|
1361
|
+
className={cn(styles.base, checked ? 'bg-primary' : 'bg-border', className)}
|
|
1362
|
+
{...props}
|
|
1426
1363
|
>
|
|
1427
|
-
<span
|
|
1428
|
-
className={cn(
|
|
1429
|
-
styles.thumb,
|
|
1430
|
-
checked
|
|
1431
|
-
? 'translate-x-[25px]'
|
|
1432
|
-
: 'translate-x-[3px]'
|
|
1433
|
-
)}
|
|
1434
|
-
/>
|
|
1364
|
+
<span className={cn(styles.thumb, checked ? 'translate-x-[25px]' : 'translate-x-[3px]')} />
|
|
1435
1365
|
</button>
|
|
1436
1366
|
)
|
|
1437
1367
|
}
|
|
@@ -1455,14 +1385,6 @@ interface TabsCtx {
|
|
|
1455
1385
|
setValue: (v: string) => void
|
|
1456
1386
|
}
|
|
1457
1387
|
|
|
1458
|
-
const Ctx = React.createContext<TabsCtx | null>(null)
|
|
1459
|
-
|
|
1460
|
-
function useTabs() {
|
|
1461
|
-
const ctx = React.useContext(Ctx)
|
|
1462
|
-
if (!ctx) throw new Error('Tabs compound used outside <Tabs>')
|
|
1463
|
-
return ctx
|
|
1464
|
-
}
|
|
1465
|
-
|
|
1466
1388
|
function TabsRoot({
|
|
1467
1389
|
children,
|
|
1468
1390
|
defaultValue,
|
|
@@ -1476,9 +1398,7 @@ function TabsRoot({
|
|
|
1476
1398
|
onChange?: (value: string) => void
|
|
1477
1399
|
className?: string
|
|
1478
1400
|
}) {
|
|
1479
|
-
const [uncontrolled, setUncontrolled] = React.useState(
|
|
1480
|
-
defaultValue ?? ''
|
|
1481
|
-
)
|
|
1401
|
+
const [uncontrolled, setUncontrolled] = React.useState(defaultValue ?? '')
|
|
1482
1402
|
const value = controlled ?? uncontrolled
|
|
1483
1403
|
const setValue = React.useCallback(
|
|
1484
1404
|
(v: string) => {
|
|
@@ -1513,21 +1433,19 @@ function Tab({
|
|
|
1513
1433
|
value: tabValue,
|
|
1514
1434
|
children,
|
|
1515
1435
|
className,
|
|
1436
|
+
...props
|
|
1516
1437
|
}: {
|
|
1517
1438
|
value: string
|
|
1518
1439
|
children: React.ReactNode
|
|
1519
1440
|
className?: string
|
|
1520
|
-
}) {
|
|
1441
|
+
} & Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'onClick'>) {
|
|
1521
1442
|
const { value, setValue } = useTabs()
|
|
1522
1443
|
const isActive = value === tabValue
|
|
1523
1444
|
return (
|
|
1524
1445
|
<button
|
|
1525
|
-
className={cn(
|
|
1526
|
-
styles.tab,
|
|
1527
|
-
isActive ? styles.active : styles.inactive,
|
|
1528
|
-
className
|
|
1529
|
-
)}
|
|
1446
|
+
className={cn(styles.tab, isActive ? styles.active : styles.inactive, className)}
|
|
1530
1447
|
onClick={() => setValue(tabValue)}
|
|
1448
|
+
{...props}
|
|
1531
1449
|
>
|
|
1532
1450
|
{children}
|
|
1533
1451
|
</button>
|
|
@@ -1548,6 +1466,14 @@ function Panel({
|
|
|
1548
1466
|
return <div className={className}>{children}</div>
|
|
1549
1467
|
}
|
|
1550
1468
|
|
|
1469
|
+
const Ctx = React.createContext<TabsCtx | null>(null)
|
|
1470
|
+
|
|
1471
|
+
function useTabs() {
|
|
1472
|
+
const ctx = React.useContext(Ctx)
|
|
1473
|
+
if (!ctx) throw new Error('Tabs compound used outside <Tabs>')
|
|
1474
|
+
return ctx
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1551
1477
|
export const Tabs = Object.assign(TabsRoot, {
|
|
1552
1478
|
List,
|
|
1553
1479
|
Tab,
|
|
@@ -1568,10 +1494,10 @@ const styles = {
|
|
|
1568
1494
|
|
|
1569
1495
|
type TextareaProps = React.TextareaHTMLAttributes<HTMLTextAreaElement>
|
|
1570
1496
|
|
|
1571
|
-
export const Textarea = React.forwardRef<
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1497
|
+
export const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(({
|
|
1498
|
+
className,
|
|
1499
|
+
...props
|
|
1500
|
+
}, ref) => (
|
|
1575
1501
|
<textarea
|
|
1576
1502
|
ref={ref}
|
|
1577
1503
|
className={cn(styles.base, className)}
|
|
@@ -1668,4 +1594,4 @@ export function Tooltip({
|
|
|
1668
1594
|
</span>
|
|
1669
1595
|
)
|
|
1670
1596
|
}
|
|
1671
|
-
`;var R=[{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:"button",description:"Button with variants, sizes, loading state, and icon slots",dependencies:[],npmDependencies:[]},{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:"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:"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:"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:[]}],
|
|
1597
|
+
`;var R=[{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:"button",description:"Button with variants, sizes, loading state, and icon slots",dependencies:[],npmDependencies:[]},{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:"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:"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:"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:[]}],P={accordion:W,alert:X,avatar:q,badge:J,button:K,card:Q,checkbox:Y,dialog:Z,dropdown:ee,input:te,popover:oe,progress:ne,select:re,separator:se,switch:ae,tabs:ce,textarea:ie,theme:G,toast:le,tooltip:de};async function pe(t){let n=process.cwd();e.intro("drivn add");let c=V(n);if(c||(e.log.error("Drivn is not initialized. Run npx drivn@latest create"),e.outro("Cancelled"),process.exit(1)),!t||!t.length){let o=await e.multiselect({message:"Select components to add",options:R.map(s=>({label:s.name,hint:s.description,value:s.name})),required:true});e.isCancel(o)&&(e.cancel("Cancelled"),process.exit(0)),t=o;}let v=t.filter(o=>!R.find(s=>s.name===o));v.length&&(e.log.error(`Unknown components: ${v.join(", ")}`),e.log.info("Available: "+R.map(o=>o.name).join(", ")),e.outro("Cancelled"),process.exit(1));let d=t.includes("theme"),m=t.filter(o=>o!=="theme"),f=new Set,b=new Set,g=o=>{if(f.has(o))return;let s=R.find(a=>a.name===o);s&&(s.dependencies.forEach(a=>g(a)),s.npmDependencies?.forEach(a=>b.add(a)),f.add(o));};m.forEach(g),d&&b.add("next-themes");let x=[...f].filter(o=>!m.includes(o));x.length&&e.log.info(`Required dependency: ${x.join(", ")}`);let l=c.typescript?"tsx":"jsx",N=join(n,c.paths.components);for(let o of f){let s=join(N,`${o}.${l}`);if(h(s)){let w=await e.confirm({message:`${o}.${l} exists. Overwrite?`,initialValue:false});if(e.isCancel(w)||!w){e.log.warn(`Skipped ${o}`);continue}}let a=P[o];a=a.replace(/@\/utils/g,`@/${c.paths.utils.replace(/^src\//,"")}`),p(s,a),e.log.success(`${o} \u2192 ${c.paths.components}/${o}.${l}`);}if(d){let o=join(N,`theme-provider.${l}`);if(h(o)){let a=await e.confirm({message:`theme-provider.${l} exists. Overwrite?`,initialValue:false});!e.isCancel(a)&&a?(p(o,P.theme),e.log.success(`theme-provider \u2192 ${c.paths.components}/theme-provider.${l}`)):e.log.warn("Skipped theme-provider");}else p(o,P.theme),e.log.success(`theme-provider \u2192 ${c.paths.components}/theme-provider.${l}`);if(c.paths.globals){let a=join(n,c.paths.globals);if(h(a)){let w=F(a);w.includes('[data-theme="dark"]')?e.log.warn("Theme tokens already exist in globals \u2014 skipped"):(p(a,w+L),e.log.success(`Theme tokens appended to ${i.cyan(c.paths.globals)}`));}else e.log.warn(`Globals file not found at ${c.paths.globals}`);}else e.log.warn('No globals path in drivn.config.json. Add "globals" to paths');let s=c.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 "${s}/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(b.size){let o=k(n),s=[...b],a=e.spinner();a.start("Installing packages");try{execSync(y(o,s),{cwd:n,stdio:"ignore"}),a.stop("Packages installed");}catch{a.stop("Failed to install packages"),e.log.warn(`Run manually: ${y(o,s)}`);}}e.outro("Done.");}var ue={version:"1.1.0"};var D=new Command;D.name("drivn").description("Drivn \u2014 Modern UI components").version(ue.version);D.command("create").description("Initialize Drivn in your project").action(U);D.command("add [components...]").description("Add components to your project").action(pe);D.parse();
|