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.
Files changed (2) hide show
  1. package/dist/index.js +192 -266
  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 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 L={next:"Next.js",react:"React"};function M(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 V="drivn.config.json";function z(t){let n=join(t,V);return existsSync(n)?JSON.parse(readFileSync(n,"utf-8")):null}function H(t,n){let c=join(t,V);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 P=`@import "tailwindcss";
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
- `,A=`
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=M(t),e.log.success(`Detected ${i.cyan(L[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),P),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),P),m.paths.globals=a,e.log.success(`Color tokens written to ${i.cyan(a)}`));}H(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'
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
- openItem: string | null
187
- toggle: (value: string) => void
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 [openItem, setOpenItem] = React.useState<string | null>(
217
- defaultValue ?? null
218
- )
219
- const toggle = React.useCallback(
220
- (value: string) =>
221
- setOpenItem((prev) => (prev === value ? null : value)),
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={{ openItem, toggle }}>
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 { openItem, toggle } = useAccordion()
258
- const value = useItemValue()
259
- const isOpen = openItem === value
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 { openItem } = useAccordion()
279
- const value = useItemValue()
280
- const isOpen = openItem === value
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 K=`import * as React from 'react'
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 X=`import * as React from 'react'
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 q=`import * as React from 'react'
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
- HTMLButtonElement,
469
- ButtonProps
470
- >(({
471
- className,
472
- variant = 'default',
473
- size = 'md',
474
- rounded = 'full',
475
- loading,
476
- disabled,
477
- leftIcon: LeftIcon,
478
- rightIcon: RightIcon,
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
- HTMLInputElement,
609
- CheckboxProps
610
- >(({
611
- className,
612
- label,
613
- checked,
614
- defaultChecked,
615
- onChange,
616
- disabled,
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
- overlay: cn(
676
- 'fixed inset-0 z-[200] flex items-center justify-center',
677
- 'bg-overlay backdrop-blur-sm',
678
- 'transition-opacity duration-150 ease-out'
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 cursor-pointer'
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 = React.useCallback(
720
- (v: boolean) => {
721
- onOpenChange?.(v)
722
- if (controlled === undefined) setUncontrolled(v)
723
- },
724
- [controlled, onOpenChange]
725
- )
671
+ const setOpen = (v: boolean) => {
672
+ onOpenChange?.(v)
673
+ if (controlled === undefined) setUncontrolled(v)
674
+ }
726
675
 
727
- return <Ctx.Provider value={{ open, setOpen }}>{children}</Ctx.Provider>
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
- if (!open) return
762
- const onKey = (e: KeyboardEvent) => {
763
- if (e.key === 'Escape') setOpen(false)
716
+ const el = ref.current
717
+ if (!el) return
718
+ const onCancel = (e: Event) => {
719
+ e.preventDefault()
720
+ setOpen(false)
764
721
  }
765
- document.addEventListener('keydown', onKey)
766
- document.body.style.overflow = 'hidden'
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
- document.removeEventListener('keydown', onKey)
769
- document.body.style.overflow = ''
737
+ el.removeEventListener('cancel', onCancel)
738
+ clearTimeout(id)
770
739
  }
771
740
  }, [open, setOpen])
772
741
 
773
742
  return (
774
- <div
775
- className={cn(
776
- styles.overlay,
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
- className={cn(
787
- styles.content,
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
- </div>
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
- const Ctx = React.createContext<DropdownCtx | null>(null)
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
- ({ className, ...props }, ref) => (
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
- styles.base,
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
- HTMLTextAreaElement,
1573
- TextareaProps
1574
- >(({ className, ...props }, ref) => (
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:[]}],I={accordion:W,alert:K,avatar:X,badge:J,button:q,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=z(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=I[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,I.theme),e.log.success(`theme-provider \u2192 ${c.paths.components}/theme-provider.${l}`)):e.log.warn("Skipped theme-provider");}else p(o,I.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+A),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.0.2"};var S=new Command;S.name("drivn").description("Drivn \u2014 Modern UI components").version(ue.version);S.command("create").description("Initialize Drivn in your project").action(U);S.command("add [components...]").description("Add components to your project").action(pe);S.parse();
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();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "drivn",
3
- "version": "1.0.2",
3
+ "version": "1.1.0",
4
4
  "description": "Modern UI components for React — add beautiful, accessible components to your project",
5
5
  "license": "MIT",
6
6
  "type": "module",