drivn 1.0.2 → 1.2.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 +1168 -349
  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 A={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 a=JSON.parse(readFileSync(n,"utf-8")),v={...a.dependencies,...a.devDependencies},p="react";v.next&&(p="next");let g=existsSync(join(t,"src")),u=existsSync(join(t,"tsconfig.json"));return {framework:p,srcDir:g,typescript:u}}var $="drivn.config.json";function V(t){let n=join(t,$);return existsSync(n)?JSON.parse(readFileSync(n,"utf-8")):null}function _(t,n){let a=join(t,$);writeFileSync(a,JSON.stringify(n,null,2));}function Ne(t){existsSync(t)||mkdirSync(t,{recursive:true});}function d(t,n){Ne(dirname(t)),writeFileSync(t,n);}function O(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,n){let a=n.join(" ");return t==="pnpm"?`pnpm add ${a}`:`npm install ${a}`}function F(t){return t==="pnpm"?"pnpm dlx":"npx"}var D=`@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
+ `,M=`
74
74
  /* Drivn Dark/Light Theme */
75
75
  :root,
76
76
  [data-theme="dark"] {
@@ -136,13 +136,13 @@ body {
136
136
  /* Special Surfaces */
137
137
  --overlay: hsl(0 0% 0% / 0.18);
138
138
  }
139
- `;var ye=`import { type ClassValue, clsx } from 'clsx'
139
+ `;var ke=`import { type ClassValue, clsx } from 'clsx'
140
140
  import { twMerge } from 'tailwind-merge'
141
141
 
142
142
  export function cn(...inputs: ClassValue[]) {
143
143
  return twMerge(clsx(inputs))
144
144
  }
145
- `,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
+ `,Pe=["src/app/globals.css","src/styles/globals.css","src/styles/globals.scss","app/globals.css"];function De(t){for(let n of Pe)if(m(join(t,n)))return n;return null}async function K(){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(A[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(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=n.srcDir?"src/components/ui":"components/ui",v=n.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:v,defaultValue:v})},{onCancel:()=>{e.cancel("Setup cancelled"),process.exit(0);}}),g={framework:n.framework,typescript:n.typescript,paths:{components:p.components,utils:p.utils},installed:[]},u=n.typescript?"ts":"js",b=join(t,p.utils,`cn.${u}`);m(b)||d(b,ke);let h=De(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),D),g.paths.globals=h,e.log.success(`Color tokens written to ${i.cyan(h)}`));}else {let r=n.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),D),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"],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 Y=`'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 W=`'use client'
164
+ `;var U=`'use client'
165
165
 
166
166
  import * as React from 'react'
167
167
  import { ChevronDown } from 'lucide-react'
@@ -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,21 @@ 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
292
  Item,
295
293
  Trigger,
296
- Content,
294
+ Content
297
295
  })
298
- `;var K=`import * as React from 'react'
296
+ `;var G=`import * as React from 'react'
299
297
  import { cn } from '@/utils/cn'
300
298
 
301
299
  const styles = {
@@ -310,9 +308,7 @@ const styles = {
310
308
  description: 'text-sm opacity-90',
311
309
  }
312
310
 
313
- type IconProp =
314
- | React.ComponentType<{ className?: string }>
315
- | React.ReactElement
311
+ type IconProp = React.ComponentType<{ className?: string }> | React.ReactElement
316
312
 
317
313
  interface AlertProps {
318
314
  variant?: keyof typeof styles.variants
@@ -345,7 +341,7 @@ export function Alert({
345
341
  </div>
346
342
  )
347
343
  }
348
- `;var X=`import * as React from 'react'
344
+ `;var W=`import * as React from 'react'
349
345
  import { cn } from '@/utils/cn'
350
346
 
351
347
  const styles = {
@@ -389,7 +385,7 @@ export function Avatar({
389
385
  </div>
390
386
  )
391
387
  }
392
- `;var J=`import * as React from 'react'
388
+ `;var X=`import * as React from 'react'
393
389
  import { cn } from '@/utils/cn'
394
390
 
395
391
  const styles = {
@@ -412,107 +408,974 @@ interface BadgeProps {
412
408
  children: React.ReactNode
413
409
  }
414
410
 
415
- export function Badge({ variant = 'default', className, children }: BadgeProps) {
411
+ export function Badge({ variant = 'default', className, children }: BadgeProps) {
412
+ return (
413
+ <span className={cn(styles.base, styles.variants[variant], className)}>
414
+ {children}
415
+ </span>
416
+ )
417
+ }
418
+ `;var q=`import * as React from 'react'
419
+ import { Loader2 } from 'lucide-react'
420
+ import { cn } from '@/utils/cn'
421
+
422
+ const styles = {
423
+ base: cn(
424
+ 'inline-flex items-center justify-center',
425
+ 'font-semibold transition-all duration-150',
426
+ 'cursor-pointer disabled:opacity-50',
427
+ 'disabled:pointer-events-none'
428
+ ),
429
+ sizes: {
430
+ sm: 'h-8 px-3 text-sm gap-1.5',
431
+ md: 'h-10 px-4 text-sm gap-2',
432
+ lg: 'h-12 px-6 text-base gap-2',
433
+ },
434
+ variants: {
435
+ default: 'bg-foreground text-background hover:scale-[1.02]',
436
+ secondary: cn(
437
+ 'bg-card text-foreground border border-border',
438
+ 'hover:bg-accent hover:border-border'
439
+ ),
440
+ outline: 'border border-border text-foreground hover:border-foreground/20',
441
+ destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90',
442
+ },
443
+ rounded: {
444
+ md: 'rounded-md',
445
+ full: 'rounded-full',
446
+ },
447
+ }
448
+
449
+ type IconProp = React.ComponentType<{ className?: string }> | React.ReactElement
450
+
451
+ interface ButtonProps
452
+ extends React.ButtonHTMLAttributes<HTMLButtonElement> {
453
+ variant?: keyof typeof styles.variants
454
+ size?: keyof typeof styles.sizes
455
+ rounded?: keyof typeof styles.rounded
456
+ loading?: boolean
457
+ leftIcon?: IconProp
458
+ rightIcon?: IconProp
459
+ }
460
+
461
+ export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(({
462
+ className,
463
+ variant = 'default',
464
+ size = 'md',
465
+ rounded = 'full',
466
+ loading,
467
+ disabled,
468
+ leftIcon: LeftIcon,
469
+ rightIcon: RightIcon,
470
+ children,
471
+ ...props
472
+ }, ref) => (
473
+ <button
474
+ ref={ref}
475
+ disabled={loading || disabled}
476
+ className={cn(styles.base, styles.sizes[size], styles.variants[variant], styles.rounded[rounded], className)}
477
+ {...props}
478
+ >
479
+ {loading && (
480
+ <Loader2 className="h-4 w-4 animate-spin" />
481
+ )}
482
+ {!loading && LeftIcon && (
483
+ React.isValidElement(LeftIcon)
484
+ ? LeftIcon
485
+ : <LeftIcon />
486
+ )}
487
+ {children}
488
+ {!loading && RightIcon && (
489
+ React.isValidElement(RightIcon)
490
+ ? RightIcon
491
+ : <RightIcon />
492
+ )}
493
+ </button>
494
+ )
495
+ )
496
+
497
+ Button.displayName = 'Button'
498
+ `;var J=`'use client'
499
+
500
+ import * as React from 'react'
501
+ import {
502
+ DayPicker,
503
+ type DateRange,
504
+ type Locale,
505
+ type PropsBase,
506
+ type PropsSingle,
507
+ type PropsRange,
508
+ } from 'react-day-picker'
509
+ import { ChevronDown, ChevronLeft, ChevronRight } from 'lucide-react'
510
+ import { cn } from '@/utils/cn'
511
+
512
+ const styles = {
513
+ root: 'p-3 bg-card border border-border rounded-[10px] text-sm',
514
+ classNames: {
515
+ months: 'relative flex gap-4',
516
+ month: 'flex flex-col gap-4',
517
+ month_caption: 'flex items-center justify-center h-7',
518
+ caption_label: 'text-sm font-medium text-foreground',
519
+ nav: 'absolute inset-x-0 top-0 flex items-center justify-between h-7',
520
+ button_previous: cn(
521
+ 'inline-flex items-center justify-center',
522
+ 'w-7 h-7 rounded-md text-muted-foreground',
523
+ 'hover:text-foreground hover:bg-accent',
524
+ 'transition-colors cursor-pointer'
525
+ ),
526
+ button_next: cn(
527
+ 'inline-flex items-center justify-center',
528
+ 'w-7 h-7 rounded-md text-muted-foreground',
529
+ 'hover:text-foreground hover:bg-accent',
530
+ 'transition-colors cursor-pointer'
531
+ ),
532
+ month_grid: 'border-collapse border-spacing-0',
533
+ weekdays: '',
534
+ weekday: cn(
535
+ 'w-8 pb-2 text-[0.8rem] font-medium',
536
+ 'text-muted-foreground text-center'
537
+ ),
538
+ week: '',
539
+ day: 'p-0 text-center',
540
+ day_button: cn(
541
+ 'inline-flex items-center justify-center',
542
+ 'w-8 h-8 rounded-md text-sm cursor-pointer',
543
+ 'hover:bg-accent hover:text-accent-foreground',
544
+ 'focus-visible:outline-none'
545
+ ),
546
+ today: 'font-semibold text-primary',
547
+ selected: cn(
548
+ '[&>button]:bg-primary',
549
+ '[&>button]:text-primary-foreground',
550
+ '[&>button]:hover:bg-primary',
551
+ '[&>button]:hover:text-primary-foreground'
552
+ ),
553
+ outside: 'text-muted-foreground/40',
554
+ disabled: 'text-muted-foreground/30 cursor-not-allowed',
555
+ range_middle: cn(
556
+ 'bg-accent text-accent-foreground',
557
+ 'hover:bg-accent hover:text-accent-foreground',
558
+ 'rounded-none [&>button]:rounded-none'
559
+ ),
560
+ chevron: 'w-4 h-4',
561
+ dropdown: cn(
562
+ 'appearance-none bg-transparent text-sm',
563
+ 'font-medium text-foreground cursor-pointer',
564
+ 'border-none outline-none'
565
+ ),
566
+ week_number: cn(
567
+ 'w-8 text-[0.75rem]',
568
+ 'text-muted-foreground/50 text-center font-normal'
569
+ ),
570
+ hidden: 'invisible',
571
+ },
572
+ dropdownOverrides: {
573
+ dropdowns: 'flex items-center gap-2 justify-center',
574
+ dropdown_root: 'relative inline-flex items-center',
575
+ dropdown: 'absolute inset-0 opacity-0 cursor-pointer w-full z-10',
576
+ caption_label: cn(
577
+ 'inline-flex items-center text-sm',
578
+ 'font-medium text-foreground',
579
+ 'pointer-events-none whitespace-nowrap'
580
+ ),
581
+ chevron: 'w-3 h-3 ml-0.5 text-muted-foreground',
582
+ },
583
+ rangeActive: {
584
+ range_start: cn(
585
+ 'bg-primary text-primary-foreground',
586
+ 'rounded-l-md [&>button]:rounded-r-none'
587
+ ),
588
+ range_end: cn(
589
+ 'bg-primary text-primary-foreground',
590
+ 'rounded-r-md [&>button]:rounded-l-none'
591
+ ),
592
+ },
593
+ }
594
+
595
+ const variantConfig = {
596
+ default: {},
597
+ weekNumbers: { showWeekNumber: true },
598
+ dropdown: { captionLayout: 'dropdown' as const },
599
+ }
600
+
601
+ export type CalendarVariant = keyof typeof variantConfig
602
+
603
+ type CalendarProps = Omit<PropsBase, 'mode'> & Omit<PropsSingle, 'mode'> & { variant?: CalendarVariant; fromYear?: number; toYear?: number }
604
+
605
+ type RangeProps = Omit<PropsBase, 'mode'> & Omit<PropsRange, 'mode'>
606
+
607
+ function Chevron(props: { orientation?: 'left' | 'right' | 'up' | 'down'; size?: number; disabled?: boolean; className?: string }) {
608
+ const icons = { left: ChevronLeft, right: ChevronRight, down: ChevronDown, up: ChevronRight }
609
+ const Icon = icons[props.orientation ?? 'right']
610
+ return <Icon className={props.className} />
611
+ }
612
+
613
+ const currentYear = new Date().getFullYear()
614
+
615
+ function CalendarRoot({
616
+ variant = 'default',
617
+ fromYear = currentYear - 20,
618
+ toYear = currentYear + 20,
619
+ className,
620
+ classNames: userClassNames,
621
+ ...props
622
+ }: CalendarProps) {
623
+ const dropdownRange = variant === 'dropdown' ? {
624
+ startMonth: new Date(fromYear, 0),
625
+ endMonth: new Date(toYear, 11),
626
+ } : {}
627
+
628
+ return (
629
+ <DayPicker
630
+ mode="single"
631
+ {...variantConfig[variant]}
632
+ {...dropdownRange}
633
+ classNames={{
634
+ ...styles.classNames,
635
+ ...(variant === 'dropdown' && styles.dropdownOverrides),
636
+ ...userClassNames,
637
+ }}
638
+ components={{ Chevron }}
639
+ className={cn(styles.root, className)}
640
+ {...props}
641
+ />
642
+ )
643
+ }
644
+
645
+ function Range({
646
+ className,
647
+ classNames: userClassNames,
648
+ selected,
649
+ ...props
650
+ }: RangeProps) {
651
+ const hasRange = selected?.from && selected?.to && selected.from.getTime() !== selected.to.getTime()
652
+
653
+ return (
654
+ <DayPicker
655
+ mode="range"
656
+ selected={selected}
657
+ classNames={{
658
+ ...styles.classNames,
659
+ ...(hasRange && styles.rangeActive),
660
+ ...userClassNames,
661
+ }}
662
+ components={{ Chevron }}
663
+ className={cn(styles.root, className)}
664
+ {...props}
665
+ />
666
+ )
667
+ }
668
+
669
+ export { type DateRange, type Locale }
670
+
671
+ export const Calendar = Object.assign(CalendarRoot, {
672
+ Range
673
+ })
674
+ `;var Q=`'use client'
675
+
676
+ import * as React from 'react'
677
+ import { CalendarDays } from 'lucide-react'
678
+ import { cn } from '@/utils/cn'
679
+ import {
680
+ Calendar,
681
+ type CalendarVariant,
682
+ type DateRange,
683
+ type Locale,
684
+ } from '@/components/ui/calendar'
685
+
686
+ const styles = {
687
+ base: 'relative',
688
+ trigger: cn(
689
+ 'flex items-center gap-2 w-full h-10 px-3',
690
+ 'border border-input rounded-[10px] text-sm',
691
+ 'text-foreground transition-colors cursor-pointer',
692
+ 'focus:outline-none',
693
+ 'disabled:opacity-50 disabled:cursor-default'
694
+ ),
695
+ placeholder: 'text-muted-foreground',
696
+ icon: 'w-4 h-4 text-muted-foreground shrink-0',
697
+ text: 'flex-1 truncate text-left',
698
+ content: cn(
699
+ 'absolute top-full left-0 mt-1 z-50',
700
+ 'transition-[opacity,scale] duration-150 ease-out'
701
+ ),
702
+ }
703
+
704
+ type FormatDateFn = (date: Date) => string
705
+
706
+ interface DatePickerBaseProps {
707
+ placeholder?: string
708
+ formatDate?: FormatDateFn
709
+ disabled?: boolean
710
+ locale?: Partial<Locale>
711
+ defaultMonth?: Date
712
+ className?: string
713
+ }
714
+
715
+ interface DatePickerProps extends DatePickerBaseProps {
716
+ selected?: Date
717
+ onSelect?: (date: Date | undefined) => void
718
+ variant?: CalendarVariant
719
+ fromYear?: number
720
+ toYear?: number
721
+ }
722
+
723
+ interface DatePickerRangeProps extends DatePickerBaseProps {
724
+ selected?: DateRange
725
+ onSelect?: (range: DateRange | undefined) => void
726
+ }
727
+
728
+ function formatRangeLabel(
729
+ range: DateRange,
730
+ fmt: FormatDateFn
731
+ ): string {
732
+ if (!range.from) return ''
733
+ if (!range.to) return fmt(range.from)
734
+ return \\\`\\\${fmt(range.from)} \u2013 \\\${fmt(range.to)}\\\`
735
+ }
736
+
737
+ function DatePickerRoot({
738
+ selected,
739
+ onSelect,
740
+ placeholder = 'Pick a date',
741
+ formatDate,
742
+ disabled = false,
743
+ locale,
744
+ variant = 'default',
745
+ fromYear,
746
+ toYear,
747
+ defaultMonth,
748
+ className,
749
+ }: DatePickerProps) {
750
+ const fmt = formatDate ?? ((d: Date) =>
751
+ d.toLocaleDateString(locale?.code ?? 'en-US', { month: 'short', day: 'numeric', year: 'numeric' }))
752
+ const [open, setOpen] = React.useState(false)
753
+ const ref = React.useRef<HTMLDivElement>(null)
754
+
755
+ React.useEffect(() => {
756
+ if (!open) return
757
+ const onMouseDown = (e: MouseEvent) => {
758
+ if (!ref.current?.contains(e.target as Node)) {
759
+ setOpen(false)
760
+ }
761
+ }
762
+ document.addEventListener('mousedown', onMouseDown)
763
+ return () => {
764
+ document.removeEventListener('mousedown', onMouseDown)
765
+ }
766
+ }, [open])
767
+
768
+ React.useEffect(() => {
769
+ if (!open) return
770
+ const onKeyDown = (e: KeyboardEvent) => {
771
+ if (e.key === 'Escape') setOpen(false)
772
+ }
773
+ document.addEventListener('keydown', onKeyDown)
774
+ return () => {
775
+ document.removeEventListener('keydown', onKeyDown)
776
+ }
777
+ }, [open])
778
+
779
+ const handleSelect = React.useCallback(
780
+ (date: Date | undefined) => {
781
+ onSelect?.(date)
782
+ setOpen(false)
783
+ },
784
+ [onSelect]
785
+ )
786
+
787
+ return (
788
+ <div ref={ref} className={cn(styles.base, className)}>
789
+ <button
790
+ type="button"
791
+ className={styles.trigger}
792
+ disabled={disabled}
793
+ onClick={() => setOpen((v) => !v)}
794
+ >
795
+ <CalendarDays className={styles.icon} />
796
+ <span className={cn(styles.text, !selected && styles.placeholder)}>
797
+ {selected ? fmt(selected) : placeholder}
798
+ </span>
799
+ </button>
800
+ <div className={cn(styles.content, open ? 'opacity-100 scale-100' : 'opacity-0 scale-95 pointer-events-none')}>
801
+ <Calendar
802
+ variant={variant}
803
+ locale={locale}
804
+ selected={selected}
805
+ onSelect={handleSelect}
806
+ defaultMonth={defaultMonth ?? selected}
807
+ {...(fromYear !== undefined && { fromYear })}
808
+ {...(toYear !== undefined && { toYear })}
809
+ />
810
+ </div>
811
+ </div>
812
+ )
813
+ }
814
+
815
+ function Range({
816
+ selected,
817
+ onSelect,
818
+ placeholder = 'Pick a date range',
819
+ formatDate,
820
+ disabled = false,
821
+ locale,
822
+ defaultMonth,
823
+ className,
824
+ }: DatePickerRangeProps) {
825
+ const fmt = formatDate ?? ((d: Date) =>
826
+ d.toLocaleDateString(locale?.code ?? 'en-US', { month: 'short', day: 'numeric', year: 'numeric' }))
827
+ const [open, setOpen] = React.useState(false)
828
+ const ref = React.useRef<HTMLDivElement>(null)
829
+
830
+ React.useEffect(() => {
831
+ if (!open) return
832
+ const onMouseDown = (e: MouseEvent) => {
833
+ if (!ref.current?.contains(e.target as Node)) {
834
+ setOpen(false)
835
+ }
836
+ }
837
+ document.addEventListener('mousedown', onMouseDown)
838
+ return () => {
839
+ document.removeEventListener('mousedown', onMouseDown)
840
+ }
841
+ }, [open])
842
+
843
+ React.useEffect(() => {
844
+ if (!open) return
845
+ const onKeyDown = (e: KeyboardEvent) => {
846
+ if (e.key === 'Escape') setOpen(false)
847
+ }
848
+ document.addEventListener('keydown', onKeyDown)
849
+ return () => {
850
+ document.removeEventListener('keydown', onKeyDown)
851
+ }
852
+ }, [open])
853
+
854
+ const handleSelect = React.useCallback(
855
+ (range: DateRange | undefined) => {
856
+ onSelect?.(range)
857
+ const complete = range?.from && range?.to
858
+ && range.from.getTime() !== range.to.getTime()
859
+ if (complete) setOpen(false)
860
+ },
861
+ [onSelect]
862
+ )
863
+
864
+ const label = selected
865
+ ? formatRangeLabel(selected, fmt)
866
+ : undefined
867
+
868
+ return (
869
+ <div ref={ref} className={cn(styles.base, className)}>
870
+ <button
871
+ type="button"
872
+ className={styles.trigger}
873
+ disabled={disabled}
874
+ onClick={() => setOpen((v) => !v)}
875
+ >
876
+ <CalendarDays className={styles.icon} />
877
+ <span className={cn(styles.text, !label && styles.placeholder)}>
878
+ {label ?? placeholder}
879
+ </span>
880
+ </button>
881
+ <div className={cn(styles.content, open ? 'opacity-100 scale-100' : 'opacity-0 scale-95 pointer-events-none')}>
882
+ <Calendar.Range
883
+ locale={locale}
884
+ selected={selected}
885
+ onSelect={handleSelect}
886
+ defaultMonth={defaultMonth ?? selected?.from}
887
+ />
888
+ </div>
889
+ </div>
890
+ )
891
+ }
892
+
893
+ export { type DateRange, type Locale }
894
+
895
+ export const DatePicker = Object.assign(DatePickerRoot, {
896
+ Range,
897
+ })
898
+ `;var Z=`'use client'
899
+
900
+ import * as React from 'react'
901
+ import { Command as CommandPrimitive } from 'cmdk'
902
+ import { Search } from 'lucide-react'
903
+ import { cn } from '@/utils/cn'
904
+ import { Dialog } from '@/components/ui/dialog'
905
+
906
+ const styles = {
907
+ root: cn(
908
+ 'flex flex-col overflow-hidden',
909
+ 'bg-card border border-border rounded-[10px]'
910
+ ),
911
+ input: {
912
+ wrapper: cn(
913
+ 'flex items-center gap-2 px-3',
914
+ 'border-b border-border'
915
+ ),
916
+ icon: 'w-4 h-4 shrink-0 text-muted-foreground',
917
+ field: cn(
918
+ 'flex h-10 w-full bg-transparent py-2',
919
+ 'text-sm text-foreground outline-none',
920
+ 'placeholder:text-muted-foreground',
921
+ 'disabled:cursor-not-allowed disabled:opacity-50'
922
+ ),
923
+ },
924
+ list: cn(
925
+ 'h-[300px] overflow-y-auto overflow-x-hidden p-1',
926
+ '[&_[cmdk-list-sizer]]:space-y-1'
927
+ ),
928
+ empty: cn(
929
+ 'py-6 text-center text-sm',
930
+ 'text-muted-foreground'
931
+ ),
932
+ loading: cn(
933
+ 'py-6 text-center text-sm',
934
+ 'text-muted-foreground'
935
+ ),
936
+ group: cn(
937
+ 'overflow-hidden',
938
+ '[&_[cmdk-group-heading]]:px-2',
939
+ '[&_[cmdk-group-heading]]:py-1.5',
940
+ '[&_[cmdk-group-heading]]:text-xs',
941
+ '[&_[cmdk-group-heading]]:font-medium',
942
+ '[&_[cmdk-group-heading]]:text-muted-foreground'
943
+ ),
944
+ item: cn(
945
+ 'relative flex items-center gap-2 px-2 py-1.5',
946
+ 'text-sm rounded-lg cursor-default select-none',
947
+ 'data-[selected=true]:bg-accent',
948
+ 'data-[selected=true]:text-accent-foreground',
949
+ 'data-[disabled=true]:pointer-events-none',
950
+ 'data-[disabled=true]:opacity-50'
951
+ ),
952
+ separator: '-mx-1 h-px bg-border',
953
+ shortcut: cn(
954
+ 'ml-auto text-xs tracking-widest',
955
+ 'text-muted-foreground'
956
+ ),
957
+ }
958
+
959
+ function CommandRoot({
960
+ className,
961
+ ...props
962
+ }: React.ComponentProps<typeof CommandPrimitive>) {
963
+ return (
964
+ <CommandPrimitive
965
+ className={cn(styles.root, className)}
966
+ {...props}
967
+ />
968
+ )
969
+ }
970
+
971
+ function Input({
972
+ className,
973
+ ...props
974
+ }: React.ComponentProps<typeof CommandPrimitive.Input>) {
975
+ return (
976
+ <div className={styles.input.wrapper}>
977
+ <Search className={styles.input.icon} />
978
+ <CommandPrimitive.Input
979
+ className={cn(styles.input.field, className)}
980
+ {...props}
981
+ />
982
+ </div>
983
+ )
984
+ }
985
+
986
+ function List({
987
+ className,
988
+ ...props
989
+ }: React.ComponentProps<typeof CommandPrimitive.List>) {
990
+ return (
991
+ <CommandPrimitive.List
992
+ className={cn(styles.list, className)}
993
+ {...props}
994
+ />
995
+ )
996
+ }
997
+
998
+ function Empty({
999
+ className,
1000
+ children,
1001
+ ...props
1002
+ }: React.ComponentProps<typeof CommandPrimitive.Empty>) {
1003
+ return (
1004
+ <CommandPrimitive.Empty
1005
+ className={cn(styles.empty, className)}
1006
+ {...props}
1007
+ >
1008
+ {children ?? 'No results found.'}
1009
+ </CommandPrimitive.Empty>
1010
+ )
1011
+ }
1012
+
1013
+ function Group({
1014
+ className,
1015
+ ...props
1016
+ }: React.ComponentProps<typeof CommandPrimitive.Group>) {
1017
+ return (
1018
+ <CommandPrimitive.Group
1019
+ className={cn(styles.group, className)}
1020
+ {...props}
1021
+ />
1022
+ )
1023
+ }
1024
+
1025
+ function Item({
1026
+ className,
1027
+ ...props
1028
+ }: React.ComponentProps<typeof CommandPrimitive.Item>) {
1029
+ return (
1030
+ <CommandPrimitive.Item
1031
+ className={cn(styles.item, className)}
1032
+ {...props}
1033
+ />
1034
+ )
1035
+ }
1036
+
1037
+ function Separator({
1038
+ className,
1039
+ ...props
1040
+ }: React.ComponentProps<typeof CommandPrimitive.Separator>) {
1041
+ return (
1042
+ <CommandPrimitive.Separator
1043
+ className={cn(styles.separator, className)}
1044
+ {...props}
1045
+ />
1046
+ )
1047
+ }
1048
+
1049
+ function Loading({
1050
+ className,
1051
+ ...props
1052
+ }: React.ComponentProps<typeof CommandPrimitive.Loading>) {
1053
+ return (
1054
+ <CommandPrimitive.Loading
1055
+ className={cn(styles.loading, className)}
1056
+ {...props}
1057
+ />
1058
+ )
1059
+ }
1060
+
1061
+ function Shortcut({
1062
+ className,
1063
+ ...props
1064
+ }: React.HTMLAttributes<HTMLElement>) {
1065
+ return (
1066
+ <kbd
1067
+ className={cn(styles.shortcut, className)}
1068
+ {...props}
1069
+ />
1070
+ )
1071
+ }
1072
+
1073
+ function CommandDialog({
1074
+ open,
1075
+ onOpenChange,
1076
+ label,
1077
+ className,
1078
+ children,
1079
+ }: {
1080
+ open: boolean
1081
+ onOpenChange: (open: boolean) => void
1082
+ label?: string
1083
+ className?: string
1084
+ children: React.ReactNode
1085
+ }) {
1086
+ React.useEffect(() => {
1087
+ const onKeyDown = (e: KeyboardEvent) => {
1088
+ if (e.key === 'k' && (e.metaKey || e.ctrlKey)) {
1089
+ e.preventDefault()
1090
+ onOpenChange(!open)
1091
+ }
1092
+ }
1093
+ document.addEventListener('keydown', onKeyDown)
1094
+ return () => {
1095
+ document.removeEventListener('keydown', onKeyDown)
1096
+ }
1097
+ }, [open, onOpenChange])
1098
+
1099
+ return (
1100
+ <Dialog open={open} onOpenChange={onOpenChange}>
1101
+ <Dialog.Content
1102
+ className={cn(
1103
+ 'p-0 max-w-lg rounded-[10px]',
1104
+ className
1105
+ )}
1106
+ >
1107
+ <CommandPrimitive
1108
+ label={label}
1109
+ className="flex flex-col overflow-hidden"
1110
+ >
1111
+ {children}
1112
+ </CommandPrimitive>
1113
+ </Dialog.Content>
1114
+ </Dialog>
1115
+ )
1116
+ }
1117
+
1118
+ export const Command = Object.assign(CommandRoot, {
1119
+ Input,
1120
+ List,
1121
+ Empty,
1122
+ Group,
1123
+ Item,
1124
+ Separator,
1125
+ Loading,
1126
+ Shortcut,
1127
+ Dialog: CommandDialog,
1128
+ })
1129
+ `;var ee=`'use client'
1130
+
1131
+ import * as React from 'react'
1132
+ import useEmblaCarousel, { type UseEmblaCarouselType } from 'embla-carousel-react'
1133
+ import { ChevronLeft, ChevronRight } from 'lucide-react'
1134
+ import { cn } from '@/utils/cn'
1135
+ import { Button } from '@/components/ui/button'
1136
+
1137
+ type CarouselApi = UseEmblaCarouselType[1]
1138
+ type CarouselOptions = Parameters<typeof useEmblaCarousel>[0]
1139
+ type CarouselPlugins = Parameters<typeof useEmblaCarousel>[1]
1140
+
1141
+ const styles = {
1142
+ root: 'relative focus-visible:outline-none',
1143
+ content: {
1144
+ viewport: 'overflow-hidden',
1145
+ container: 'flex',
1146
+ horizontal: '-ml-4',
1147
+ vertical: '-mt-4 flex-col h-full',
1148
+ },
1149
+ item: {
1150
+ base: 'min-w-0 shrink-0 grow-0 basis-full',
1151
+ horizontal: 'pl-4',
1152
+ vertical: 'pt-4',
1153
+ },
1154
+ arrow: cn(
1155
+ 'absolute top-1/2 -translate-y-1/2',
1156
+ 'w-8 px-0 bg-card/80 backdrop-blur-sm'
1157
+ ),
1158
+ dots: {
1159
+ wrapper: 'flex justify-center gap-1.5 mt-3',
1160
+ dot: cn(
1161
+ 'w-2 h-2 rounded-full transition-colors',
1162
+ 'bg-border cursor-pointer'
1163
+ ),
1164
+ active: 'bg-foreground',
1165
+ },
1166
+ }
1167
+
1168
+ interface CarouselCtx {
1169
+ emblaRef: UseEmblaCarouselType[0]
1170
+ api: CarouselApi
1171
+ canScrollPrev: boolean
1172
+ canScrollNext: boolean
1173
+ selectedIndex: number
1174
+ scrollSnaps: number[]
1175
+ orientation: 'horizontal' | 'vertical'
1176
+ }
1177
+
1178
+ interface CarouselRootProps
1179
+ extends React.HTMLAttributes<HTMLDivElement> {
1180
+ opts?: CarouselOptions
1181
+ plugins?: CarouselPlugins
1182
+ orientation?: 'horizontal' | 'vertical'
1183
+ setApi?: (api: CarouselApi) => void
1184
+ }
1185
+
1186
+ function CarouselRoot({
1187
+ opts,
1188
+ plugins,
1189
+ orientation = 'horizontal',
1190
+ setApi,
1191
+ className,
1192
+ children,
1193
+ ...props
1194
+ }: CarouselRootProps) {
1195
+ const [emblaRef, api] = useEmblaCarousel({ ...opts, axis: orientation === 'vertical' ? 'y' : 'x' }, plugins)
1196
+ const [canScrollPrev, setCanScrollPrev] = React.useState(false)
1197
+ const [canScrollNext, setCanScrollNext] = React.useState(false)
1198
+ const [selectedIndex, setSelectedIndex] = React.useState(0)
1199
+ const [scrollSnaps, setScrollSnaps] = React.useState<number[]>([])
1200
+
1201
+ const onSelect = React.useCallback((emblaApi: NonNullable<CarouselApi>) => {
1202
+ setCanScrollPrev(emblaApi.canScrollPrev())
1203
+ setCanScrollNext(emblaApi.canScrollNext())
1204
+ setSelectedIndex(emblaApi.selectedScrollSnap())
1205
+ }, [])
1206
+
1207
+ React.useEffect(() => {
1208
+ if (!api) return
1209
+ setScrollSnaps(api.scrollSnapList())
1210
+ onSelect(api)
1211
+ api.on('reInit', onSelect)
1212
+ api.on('select', onSelect)
1213
+ return () => {
1214
+ api.off('reInit', onSelect)
1215
+ api.off('select', onSelect)
1216
+ }
1217
+ }, [api, onSelect])
1218
+
1219
+ React.useEffect(() => {
1220
+ if (setApi && api) setApi(api)
1221
+ }, [api, setApi])
1222
+
1223
+ const handleKeyDown = React.useCallback((e: React.KeyboardEvent) => {
1224
+ if (!api) return
1225
+ if (e.key === 'ArrowLeft') {
1226
+ e.preventDefault()
1227
+ api.scrollPrev()
1228
+ } else if (e.key === 'ArrowRight') {
1229
+ e.preventDefault()
1230
+ api.scrollNext()
1231
+ }
1232
+ }, [api])
1233
+
1234
+ return (
1235
+ <Ctx.Provider
1236
+ value={{
1237
+ emblaRef,
1238
+ api,
1239
+ canScrollPrev,
1240
+ canScrollNext,
1241
+ selectedIndex,
1242
+ scrollSnaps,
1243
+ orientation,
1244
+ }}
1245
+ >
1246
+ <div
1247
+ role="region"
1248
+ aria-roledescription="carousel"
1249
+ tabIndex={0}
1250
+ onKeyDown={handleKeyDown}
1251
+ className={cn(styles.root, className)}
1252
+ {...props}
1253
+ >
1254
+ {children}
1255
+ </div>
1256
+ </Ctx.Provider>
1257
+ )
1258
+ }
1259
+
1260
+ function Content({
1261
+ className,
1262
+ children,
1263
+ }: {
1264
+ className?: string
1265
+ children: React.ReactNode
1266
+ }) {
1267
+ const { emblaRef, orientation } = useCarousel()
1268
+ return (
1269
+ <div className={cn(styles.content.viewport, className)} ref={emblaRef}>
1270
+ <div className={cn(styles.content.container, orientation === 'vertical' ? styles.content.vertical : styles.content.horizontal)}>
1271
+ {children}
1272
+ </div>
1273
+ </div>
1274
+ )
1275
+ }
1276
+
1277
+ function Item({
1278
+ className,
1279
+ children,
1280
+ }: {
1281
+ className?: string
1282
+ children: React.ReactNode
1283
+ }) {
1284
+ const { orientation } = useCarousel()
1285
+ return (
1286
+ <div
1287
+ role="group"
1288
+ aria-roledescription="slide"
1289
+ className={cn(styles.item.base, orientation === 'vertical' ? styles.item.vertical : styles.item.horizontal, className)}
1290
+ >
1291
+ {children}
1292
+ </div>
1293
+ )
1294
+ }
1295
+
1296
+ function Previous({
1297
+ className,
1298
+ variant = 'secondary',
1299
+ size = 'sm',
1300
+ ...props
1301
+ }: React.ComponentProps<typeof Button>) {
1302
+ const { api, canScrollPrev } = useCarousel()
416
1303
  return (
417
- <span className={cn(styles.base, styles.variants[variant], className)}>
418
- {children}
419
- </span>
1304
+ <Button
1305
+ variant={variant}
1306
+ size={size}
1307
+ aria-label="Previous slide"
1308
+ className={cn(styles.arrow, '-left-12', className)}
1309
+ disabled={!canScrollPrev}
1310
+ onClick={() => api?.scrollPrev()}
1311
+ {...props}
1312
+ >
1313
+ <ChevronLeft className="w-4 h-4" />
1314
+ </Button>
420
1315
  )
421
1316
  }
422
- `;var q=`import * as React from 'react'
423
- import { Loader2 } from 'lucide-react'
424
- import { cn } from '@/utils/cn'
425
1317
 
426
- const styles = {
427
- base: cn(
428
- 'inline-flex items-center justify-center',
429
- 'font-semibold transition-all duration-150',
430
- 'cursor-pointer disabled:opacity-50',
431
- 'disabled:pointer-events-none'
432
- ),
433
- sizes: {
434
- sm: 'h-8 px-3 text-sm gap-1.5',
435
- md: 'h-10 px-4 text-sm gap-2',
436
- lg: 'h-12 px-6 text-base gap-2',
437
- },
438
- variants: {
439
- default: 'bg-foreground text-background hover:scale-[1.02]',
440
- secondary: cn(
441
- 'bg-card text-foreground border border-border',
442
- 'hover:bg-accent hover:border-border'
443
- ),
444
- outline: 'border border-border text-foreground hover:border-foreground/20',
445
- destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90',
446
- },
447
- rounded: {
448
- md: 'rounded-md',
449
- full: 'rounded-full',
450
- },
1318
+ function Next({
1319
+ className,
1320
+ variant = 'secondary',
1321
+ size = 'sm',
1322
+ ...props
1323
+ }: React.ComponentProps<typeof Button>) {
1324
+ const { api, canScrollNext } = useCarousel()
1325
+ return (
1326
+ <Button
1327
+ variant={variant}
1328
+ size={size}
1329
+ aria-label="Next slide"
1330
+ className={cn(styles.arrow, '-right-12', className)}
1331
+ disabled={!canScrollNext}
1332
+ onClick={() => api?.scrollNext()}
1333
+ {...props}
1334
+ >
1335
+ <ChevronRight className="w-4 h-4" />
1336
+ </Button>
1337
+ )
451
1338
  }
452
1339
 
453
- type IconProp =
454
- | React.ComponentType<{ className?: string }>
455
- | React.ReactElement
1340
+ function Dots({
1341
+ className,
1342
+ }: {
1343
+ className?: string
1344
+ }) {
1345
+ const { api, scrollSnaps, selectedIndex } = useCarousel()
1346
+ return (
1347
+ <div className={cn(styles.dots.wrapper, className)}>
1348
+ {scrollSnaps.map((_, i) => (
1349
+ <button
1350
+ key={i}
1351
+ type="button"
1352
+ aria-label={\`Go to slide \${i + 1}\`}
1353
+ className={cn(styles.dots.dot, i === selectedIndex && styles.dots.active)}
1354
+ onClick={() => api?.scrollTo(i)}
1355
+ />
1356
+ ))}
1357
+ </div>
1358
+ )
1359
+ }
456
1360
 
457
- interface ButtonProps
458
- extends React.ButtonHTMLAttributes<HTMLButtonElement> {
459
- variant?: keyof typeof styles.variants
460
- size?: keyof typeof styles.sizes
461
- rounded?: keyof typeof styles.rounded
462
- loading?: boolean
463
- leftIcon?: IconProp
464
- rightIcon?: IconProp
1361
+ const Ctx = React.createContext<CarouselCtx | null>(null)
1362
+
1363
+ function useCarousel() {
1364
+ const ctx = React.useContext(Ctx)
1365
+ if (!ctx) throw new Error('Carousel.* used outside <Carousel>')
1366
+ return ctx
465
1367
  }
466
1368
 
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
- ) => (
484
- <button
485
- ref={ref}
486
- disabled={loading || disabled}
487
- className={cn(
488
- styles.base,
489
- styles.sizes[size],
490
- styles.variants[variant],
491
- styles.rounded[rounded],
492
- className
493
- )}
494
- {...props}
495
- >
496
- {loading && (
497
- <Loader2 className="h-4 w-4 animate-spin" />
498
- )}
499
- {!loading && LeftIcon && (
500
- React.isValidElement(LeftIcon)
501
- ? LeftIcon
502
- : <LeftIcon />
503
- )}
504
- {children}
505
- {!loading && RightIcon && (
506
- React.isValidElement(RightIcon)
507
- ? RightIcon
508
- : <RightIcon />
509
- )}
510
- </button>
511
- )
512
- )
1369
+ export type { CarouselApi }
513
1370
 
514
- Button.displayName = 'Button'
515
- `;var Q=`import * as React from 'react'
1371
+ export const Carousel = Object.assign(CarouselRoot, {
1372
+ Content,
1373
+ Item,
1374
+ Previous,
1375
+ Next,
1376
+ Dots
1377
+ })
1378
+ `;var te=`import * as React from 'react'
516
1379
  import { cn } from '@/utils/cn'
517
1380
 
518
1381
  const styles = {
@@ -577,9 +1440,9 @@ function Info({
577
1440
 
578
1441
  export const Card = Object.assign(CardRoot, {
579
1442
  Preview,
580
- Info,
1443
+ Info
581
1444
  })
582
- `;var Y=`'use client'
1445
+ `;var oe=`'use client'
583
1446
 
584
1447
  import * as React from 'react'
585
1448
  import { Check } from 'lucide-react'
@@ -596,42 +1459,25 @@ const styles = {
596
1459
  label: 'text-sm text-foreground select-none',
597
1460
  }
598
1461
 
599
- interface CheckboxProps
600
- extends Omit<
601
- React.InputHTMLAttributes<HTMLInputElement>,
602
- 'type'
603
- > {
1462
+ interface CheckboxProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'type'> {
604
1463
  label?: string
605
1464
  }
606
1465
 
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
- )
1466
+ export const Checkbox = React.forwardRef<HTMLInputElement, CheckboxProps>(({
1467
+ className,
1468
+ label,
1469
+ checked,
1470
+ defaultChecked,
1471
+ onChange,
1472
+ disabled,
1473
+ ...props
1474
+ }, ref) => {
1475
+ const [internal, setInternal] = React.useState(defaultChecked ?? false)
624
1476
  const isControlled = checked !== undefined
625
1477
  const isChecked = isControlled ? checked : internal
626
1478
 
627
1479
  return (
628
- <label
629
- className={cn(
630
- styles.base,
631
- disabled && 'opacity-50 cursor-default',
632
- className
633
- )}
634
- >
1480
+ <label className={cn(styles.base, disabled && 'opacity-50 cursor-default', className)}>
635
1481
  <input
636
1482
  ref={ref}
637
1483
  type="checkbox"
@@ -645,12 +1491,7 @@ export const Checkbox = React.forwardRef<
645
1491
  }}
646
1492
  {...props}
647
1493
  />
648
- <span
649
- className={cn(
650
- styles.box,
651
- isChecked && styles.checked
652
- )}
653
- >
1494
+ <span className={cn(styles.box, isChecked && styles.checked)}>
654
1495
  {isChecked && (
655
1496
  <Check className="w-2.5 h-2.5 text-primary-foreground" />
656
1497
  )}
@@ -664,7 +1505,7 @@ export const Checkbox = React.forwardRef<
664
1505
  )
665
1506
 
666
1507
  Checkbox.displayName = 'Checkbox'
667
- `;var Z=`'use client'
1508
+ `;var ne=`'use client'
668
1509
 
669
1510
  import * as React from 'react'
670
1511
  import { X } from 'lucide-react'
@@ -672,23 +1513,24 @@ import { cn } from '@/utils/cn'
672
1513
  import { Button } from '@/components/ui/button'
673
1514
 
674
1515
  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'
1516
+ base: cn(
1517
+ 'fixed inset-0 m-0 p-0 border-none',
1518
+ 'max-w-none max-h-none w-screen h-dvh',
1519
+ 'flex items-center justify-center bg-overlay',
1520
+ 'backdrop-blur-sm transition-opacity duration-150',
1521
+ 'ease-out'
679
1522
  ),
680
1523
  content: cn(
681
- 'relative w-full max-w-md mx-4 p-6',
1524
+ 'relative w-full max-w-md mx-4 p-6 shadow-xl',
682
1525
  'bg-card border border-border rounded-[20px]',
683
- 'shadow-xl',
684
1526
  'transition-[scale] duration-150 ease-out'
685
1527
  ),
686
1528
  title: 'text-lg font-semibold text-foreground mb-4',
687
1529
  close: cn(
688
- 'absolute top-4 right-4 w-8 h-8',
1530
+ 'absolute top-4 right-4 w-8 h-8 cursor-pointer',
689
1531
  'flex items-center justify-center rounded-full',
690
1532
  'text-muted-foreground hover:text-foreground',
691
- 'hover:bg-accent transition-colors cursor-pointer'
1533
+ 'hover:bg-accent transition-colors'
692
1534
  ),
693
1535
  }
694
1536
 
@@ -697,14 +1539,6 @@ interface DialogCtx {
697
1539
  setOpen: (v: boolean) => void
698
1540
  }
699
1541
 
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
1542
  function DialogRoot({
709
1543
  children,
710
1544
  open: controlled,
@@ -716,15 +1550,16 @@ function DialogRoot({
716
1550
  }) {
717
1551
  const [uncontrolled, setUncontrolled] = React.useState(false)
718
1552
  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
- )
1553
+ const setOpen = (v: boolean) => {
1554
+ onOpenChange?.(v)
1555
+ if (controlled === undefined) setUncontrolled(v)
1556
+ }
726
1557
 
727
- return <Ctx.Provider value={{ open, setOpen }}>{children}</Ctx.Provider>
1558
+ return (
1559
+ <Ctx.Provider value={{ open, setOpen }}>
1560
+ {children}
1561
+ </Ctx.Provider>
1562
+ )
728
1563
  }
729
1564
 
730
1565
  function Trigger({
@@ -756,43 +1591,51 @@ function Content({
756
1591
  className?: string
757
1592
  }) {
758
1593
  const { open, setOpen } = useDialog()
1594
+ const ref = React.useRef<HTMLDialogElement>(null)
1595
+ const [visible, setVisible] = React.useState(false)
759
1596
 
760
1597
  React.useEffect(() => {
761
- if (!open) return
762
- const onKey = (e: KeyboardEvent) => {
763
- if (e.key === 'Escape') setOpen(false)
1598
+ const el = ref.current
1599
+ if (!el) return
1600
+ const onCancel = (e: Event) => {
1601
+ e.preventDefault()
1602
+ setOpen(false)
764
1603
  }
765
- document.addEventListener('keydown', onKey)
766
- document.body.style.overflow = 'hidden'
1604
+ el.addEventListener('cancel', onCancel)
1605
+ if (open) {
1606
+ if (!el.open) el.showModal()
1607
+ document.body.style.overflow = 'hidden'
1608
+ requestAnimationFrame(() => setVisible(true))
1609
+ return () => {
1610
+ el.removeEventListener('cancel', onCancel)
1611
+ document.body.style.overflow = ''
1612
+ }
1613
+ }
1614
+ setVisible(false)
1615
+ const id = setTimeout(() => {
1616
+ if (el.open) el.close()
1617
+ }, 150)
767
1618
  return () => {
768
- document.removeEventListener('keydown', onKey)
769
- document.body.style.overflow = ''
1619
+ el.removeEventListener('cancel', onCancel)
1620
+ clearTimeout(id)
770
1621
  }
771
1622
  }, [open, setOpen])
772
1623
 
773
1624
  return (
774
- <div
775
- className={cn(
776
- styles.overlay,
777
- open
778
- ? 'opacity-100'
779
- : 'opacity-0 pointer-events-none'
780
- )}
1625
+ <dialog
1626
+ ref={ref}
1627
+ className={cn(styles.base, visible ? 'opacity-100' : 'opacity-0 pointer-events-none')}
781
1628
  onClick={(e) => {
782
1629
  if (e.target === e.currentTarget) setOpen(false)
783
1630
  }}
784
1631
  >
785
- <div
786
- className={cn(
787
- styles.content,
788
- open ? 'scale-100' : 'scale-95',
789
- className
1632
+ <div className={cn(styles.content, visible ? 'scale-100' : 'scale-95', className)}>
1633
+ {title && (
1634
+ <h2 className={styles.title}>{title}</h2>
790
1635
  )}
791
- >
792
- {title && <h2 className={styles.title}>{title}</h2>}
793
1636
  {children}
794
1637
  </div>
795
- </div>
1638
+ </dialog>
796
1639
  )
797
1640
  }
798
1641
 
@@ -808,12 +1651,20 @@ function Close({ className }: { className?: string }) {
808
1651
  )
809
1652
  }
810
1653
 
1654
+ const Ctx = React.createContext<DialogCtx | null>(null)
1655
+
1656
+ function useDialog() {
1657
+ const ctx = React.useContext(Ctx)
1658
+ if (!ctx) throw new Error('Dialog compound used outside <Dialog>')
1659
+ return ctx
1660
+ }
1661
+
811
1662
  export const Dialog = Object.assign(DialogRoot, {
812
1663
  Trigger,
813
1664
  Content,
814
- Close,
1665
+ Close
815
1666
  })
816
- `;var ee=`'use client'
1667
+ `;var re=`'use client'
817
1668
 
818
1669
  import * as React from 'react'
819
1670
  import { cn } from '@/utils/cn'
@@ -851,15 +1702,7 @@ interface DropdownCtx {
851
1702
  align: keyof typeof styles.align
852
1703
  }
853
1704
 
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
- }
1705
+ type IconProp = React.ComponentType<{ className?: string }> | React.ReactElement
863
1706
 
864
1707
  function DropdownRoot({
865
1708
  children,
@@ -925,50 +1768,35 @@ function Content({
925
1768
  }) {
926
1769
  const { open, align } = useDropdown()
927
1770
  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
- >
1771
+ <div className={cn(styles.content, styles.align[align], open ? 'opacity-100 scale-100' : 'opacity-0 scale-95 pointer-events-none', className)}>
938
1772
  {children}
939
1773
  </div>
940
1774
  )
941
1775
  }
942
1776
 
943
- type IconProp =
944
- | React.ComponentType<{ className?: string }>
945
- | React.ReactElement
946
-
947
1777
  function Item({
948
1778
  children,
949
1779
  onClick,
950
1780
  icon: Icon,
951
1781
  destructive,
952
1782
  className,
1783
+ ...props
953
1784
  }: {
954
1785
  children: React.ReactNode
955
1786
  onClick?: () => void
956
1787
  icon?: IconProp
957
1788
  destructive?: boolean
958
1789
  className?: string
959
- }) {
1790
+ } & Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'onClick'>) {
960
1791
  const { setOpen } = useDropdown()
961
1792
  return (
962
1793
  <button
963
- className={cn(
964
- styles.item,
965
- destructive && styles.destructive,
966
- className
967
- )}
1794
+ className={cn(styles.item, destructive && styles.destructive, className)}
968
1795
  onClick={() => {
969
1796
  onClick?.()
970
1797
  setOpen(false)
971
1798
  }}
1799
+ {...props}
972
1800
  >
973
1801
  {Icon && (
974
1802
  React.isValidElement(Icon)
@@ -1018,15 +1846,23 @@ function DropdownSeparator({
1018
1846
  )
1019
1847
  }
1020
1848
 
1849
+ const Ctx = React.createContext<DropdownCtx | null>(null)
1850
+
1851
+ function useDropdown() {
1852
+ const ctx = React.useContext(Ctx)
1853
+ if (!ctx) throw new Error('Dropdown compound used outside <Dropdown>')
1854
+ return ctx
1855
+ }
1856
+
1021
1857
  export const Dropdown = Object.assign(DropdownRoot, {
1022
1858
  Trigger,
1023
1859
  Content,
1024
1860
  Item,
1025
1861
  Group,
1026
1862
  Label,
1027
- Separator: DropdownSeparator,
1863
+ Separator: DropdownSeparator
1028
1864
  })
1029
- `;var te=`import * as React from 'react'
1865
+ `;var se=`import * as React from 'react'
1030
1866
  import { cn } from '@/utils/cn'
1031
1867
 
1032
1868
  const styles = {
@@ -1040,14 +1876,16 @@ const styles = {
1040
1876
 
1041
1877
  type InputProps = React.InputHTMLAttributes<HTMLInputElement>
1042
1878
 
1043
- export const Input = React.forwardRef<HTMLInputElement, InputProps>(
1044
- ({ className, ...props }, ref) => (
1879
+ export const Input = React.forwardRef<HTMLInputElement, InputProps>(({
1880
+ className,
1881
+ ...props
1882
+ }, ref) => (
1045
1883
  <input ref={ref} className={cn(styles.base, className)} {...props} />
1046
1884
  )
1047
1885
  )
1048
1886
 
1049
1887
  Input.displayName = 'Input'
1050
- `;var oe=`'use client'
1888
+ `;var ae=`'use client'
1051
1889
 
1052
1890
  import * as React from 'react'
1053
1891
  import { cn } from '@/utils/cn'
@@ -1075,14 +1913,6 @@ interface PopoverCtx {
1075
1913
  position: keyof typeof styles.positions
1076
1914
  }
1077
1915
 
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
1916
  function PopoverRoot({
1087
1917
  children,
1088
1918
  position = 'bottom',
@@ -1142,26 +1972,25 @@ function Content({
1142
1972
  }) {
1143
1973
  const { open, position } = usePopover()
1144
1974
  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
- >
1975
+ <div className={cn(styles.content, styles.positions[position], open ? 'opacity-100 scale-100' : 'opacity-0 scale-95 pointer-events-none', className)}>
1155
1976
  {children}
1156
1977
  </div>
1157
1978
  )
1158
1979
  }
1159
1980
 
1981
+ const Ctx = React.createContext<PopoverCtx | null>(null)
1982
+
1983
+ function usePopover() {
1984
+ const ctx = React.useContext(Ctx)
1985
+ if (!ctx) throw new Error('Popover compound used outside <Popover>')
1986
+ return ctx
1987
+ }
1988
+
1160
1989
  export const Popover = Object.assign(PopoverRoot, {
1161
1990
  Trigger,
1162
- Content,
1991
+ Content
1163
1992
  })
1164
- `;var ne=`import * as React from 'react'
1993
+ `;var ce=`import * as React from 'react'
1165
1994
  import { cn } from '@/utils/cn'
1166
1995
 
1167
1996
  const styles = {
@@ -1199,7 +2028,7 @@ export function Progress({
1199
2028
  </div>
1200
2029
  )
1201
2030
  }
1202
- `;var re=`'use client'
2031
+ `;var ie=`'use client'
1203
2032
 
1204
2033
  import * as React from 'react'
1205
2034
  import { ChevronDown } from 'lucide-react'
@@ -1238,14 +2067,6 @@ interface SelectCtx {
1238
2067
  onSelect: (v: string) => void
1239
2068
  }
1240
2069
 
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
2070
  function SelectRoot({
1250
2071
  children,
1251
2072
  value,
@@ -1290,16 +2111,18 @@ function Trigger({
1290
2111
  placeholder = 'Select...',
1291
2112
  children,
1292
2113
  className,
2114
+ ...props
1293
2115
  }: {
1294
2116
  placeholder?: string
1295
2117
  children?: React.ReactNode
1296
2118
  className?: string
1297
- }) {
2119
+ } & Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'onClick'>) {
1298
2120
  const { open, setOpen } = useSelect()
1299
2121
  return (
1300
2122
  <button
1301
2123
  className={cn(styles.trigger, className)}
1302
2124
  onClick={() => setOpen(!open)}
2125
+ {...props}
1303
2126
  >
1304
2127
  <span className={!children ? styles.placeholder : undefined}>
1305
2128
  {children ?? placeholder}
@@ -1318,15 +2141,7 @@ function Menu({
1318
2141
  }) {
1319
2142
  const { open } = useSelect()
1320
2143
  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
- >
2144
+ <div className={cn(styles.menu, open ? 'opacity-100 scale-100' : 'opacity-0 scale-95 pointer-events-none', className)}>
1330
2145
  {children}
1331
2146
  </div>
1332
2147
  )
@@ -1336,32 +2151,38 @@ function Option({
1336
2151
  value: optValue,
1337
2152
  children,
1338
2153
  className,
2154
+ ...props
1339
2155
  }: {
1340
2156
  value: string
1341
2157
  children: React.ReactNode
1342
2158
  className?: string
1343
- }) {
2159
+ } & Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'onClick'>) {
1344
2160
  const { value, onSelect } = useSelect()
1345
2161
  return (
1346
2162
  <button
1347
- className={cn(
1348
- styles.option,
1349
- optValue === value && styles.selected,
1350
- className
1351
- )}
2163
+ className={cn(styles.option, optValue === value && styles.selected, className)}
1352
2164
  onClick={() => onSelect(optValue)}
2165
+ {...props}
1353
2166
  >
1354
2167
  {children}
1355
2168
  </button>
1356
2169
  )
1357
2170
  }
1358
2171
 
2172
+ const Ctx = React.createContext<SelectCtx | null>(null)
2173
+
2174
+ function useSelect() {
2175
+ const ctx = React.useContext(Ctx)
2176
+ if (!ctx) throw new Error('Select compound used outside <Select>')
2177
+ return ctx
2178
+ }
2179
+
1359
2180
  export const Select = Object.assign(SelectRoot, {
1360
2181
  Trigger,
1361
2182
  Menu,
1362
- Option,
2183
+ Option
1363
2184
  })
1364
- `;var se=`import * as React from 'react'
2185
+ `;var le=`import * as React from 'react'
1365
2186
  import { cn } from '@/utils/cn'
1366
2187
 
1367
2188
  const styles = {
@@ -1385,7 +2206,7 @@ export function Separator({
1385
2206
  />
1386
2207
  )
1387
2208
  }
1388
- `;var ae=`'use client'
2209
+ `;var de=`'use client'
1389
2210
 
1390
2211
  import * as React from 'react'
1391
2212
  import { cn } from '@/utils/cn'
@@ -1402,40 +2223,31 @@ const styles = {
1402
2223
  ),
1403
2224
  }
1404
2225
 
1405
- interface SwitchProps {
2226
+ interface SwitchProps
2227
+ extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'onChange'> {
1406
2228
  checked?: boolean
1407
2229
  onChange?: (checked: boolean) => void
1408
- className?: string
1409
2230
  }
1410
2231
 
1411
2232
  export function Switch({
1412
2233
  checked = false,
1413
2234
  onChange,
1414
2235
  className,
2236
+ ...props
1415
2237
  }: SwitchProps) {
1416
2238
  return (
1417
2239
  <button
1418
2240
  role="switch"
1419
2241
  aria-checked={checked}
1420
2242
  onClick={() => onChange?.(!checked)}
1421
- className={cn(
1422
- styles.base,
1423
- checked ? 'bg-primary' : 'bg-border',
1424
- className
1425
- )}
2243
+ className={cn(styles.base, checked ? 'bg-primary' : 'bg-border', className)}
2244
+ {...props}
1426
2245
  >
1427
- <span
1428
- className={cn(
1429
- styles.thumb,
1430
- checked
1431
- ? 'translate-x-[25px]'
1432
- : 'translate-x-[3px]'
1433
- )}
1434
- />
2246
+ <span className={cn(styles.thumb, checked ? 'translate-x-[25px]' : 'translate-x-[3px]')} />
1435
2247
  </button>
1436
2248
  )
1437
2249
  }
1438
- `;var ce=`'use client'
2250
+ `;var pe=`'use client'
1439
2251
 
1440
2252
  import * as React from 'react'
1441
2253
  import { cn } from '@/utils/cn'
@@ -1455,14 +2267,6 @@ interface TabsCtx {
1455
2267
  setValue: (v: string) => void
1456
2268
  }
1457
2269
 
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
2270
  function TabsRoot({
1467
2271
  children,
1468
2272
  defaultValue,
@@ -1476,9 +2280,7 @@ function TabsRoot({
1476
2280
  onChange?: (value: string) => void
1477
2281
  className?: string
1478
2282
  }) {
1479
- const [uncontrolled, setUncontrolled] = React.useState(
1480
- defaultValue ?? ''
1481
- )
2283
+ const [uncontrolled, setUncontrolled] = React.useState(defaultValue ?? '')
1482
2284
  const value = controlled ?? uncontrolled
1483
2285
  const setValue = React.useCallback(
1484
2286
  (v: string) => {
@@ -1513,21 +2315,19 @@ function Tab({
1513
2315
  value: tabValue,
1514
2316
  children,
1515
2317
  className,
2318
+ ...props
1516
2319
  }: {
1517
2320
  value: string
1518
2321
  children: React.ReactNode
1519
2322
  className?: string
1520
- }) {
2323
+ } & Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'onClick'>) {
1521
2324
  const { value, setValue } = useTabs()
1522
2325
  const isActive = value === tabValue
1523
2326
  return (
1524
2327
  <button
1525
- className={cn(
1526
- styles.tab,
1527
- isActive ? styles.active : styles.inactive,
1528
- className
1529
- )}
2328
+ className={cn(styles.tab, isActive ? styles.active : styles.inactive, className)}
1530
2329
  onClick={() => setValue(tabValue)}
2330
+ {...props}
1531
2331
  >
1532
2332
  {children}
1533
2333
  </button>
@@ -1548,12 +2348,20 @@ function Panel({
1548
2348
  return <div className={className}>{children}</div>
1549
2349
  }
1550
2350
 
2351
+ const Ctx = React.createContext<TabsCtx | null>(null)
2352
+
2353
+ function useTabs() {
2354
+ const ctx = React.useContext(Ctx)
2355
+ if (!ctx) throw new Error('Tabs compound used outside <Tabs>')
2356
+ return ctx
2357
+ }
2358
+
1551
2359
  export const Tabs = Object.assign(TabsRoot, {
1552
2360
  List,
1553
2361
  Tab,
1554
- Panel,
2362
+ Panel
1555
2363
  })
1556
- `;var ie=`import * as React from 'react'
2364
+ `;var ue=`import * as React from 'react'
1557
2365
  import { cn } from '@/utils/cn'
1558
2366
 
1559
2367
  const styles = {
@@ -1568,10 +2376,10 @@ const styles = {
1568
2376
 
1569
2377
  type TextareaProps = React.TextareaHTMLAttributes<HTMLTextAreaElement>
1570
2378
 
1571
- export const Textarea = React.forwardRef<
1572
- HTMLTextAreaElement,
1573
- TextareaProps
1574
- >(({ className, ...props }, ref) => (
2379
+ export const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(({
2380
+ className,
2381
+ ...props
2382
+ }, ref) => (
1575
2383
  <textarea
1576
2384
  ref={ref}
1577
2385
  className={cn(styles.base, className)}
@@ -1580,7 +2388,7 @@ export const Textarea = React.forwardRef<
1580
2388
  ))
1581
2389
 
1582
2390
  Textarea.displayName = 'Textarea'
1583
- `;var le=`'use client'
2391
+ `;var me=`'use client'
1584
2392
 
1585
2393
  import * as React from 'react'
1586
2394
  import { Toaster as Sonner, toast } from 'sonner'
@@ -1623,7 +2431,7 @@ function Toaster() {
1623
2431
  }
1624
2432
 
1625
2433
  export { Toaster, toast }
1626
- `;var de=`import * as React from 'react'
2434
+ `;var fe=`import * as React from 'react'
1627
2435
  import { cn } from '@/utils/cn'
1628
2436
 
1629
2437
  const styles = {
@@ -1668,4 +2476,15 @@ export function Tooltip({
1668
2476
  </span>
1669
2477
  )
1670
2478
  }
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();
2479
+ `;var ge=`
2480
+ /* react-day-picker theme integration */
2481
+ .rdp-root {
2482
+ --rdp-accent-color: var(--primary);
2483
+ --rdp-accent-background-color: var(--accent);
2484
+ --rdp-day-height: 36px;
2485
+ --rdp-day-width: 36px;
2486
+ --rdp-selected-font: inherit;
2487
+ --rdp-selected-border: none;
2488
+ --rdp-day_button-border: none;
2489
+ }
2490
+ `,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:"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:"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:[]}],S={accordion:U,alert:G,avatar:W,badge:X,button:q,calendar:J,"date-picker":Q,command:Z,carousel:ee,card:te,checkbox:oe,dialog:ne,dropdown:re,input:se,popover:ae,progress:ce,select:ie,separator:le,switch:de,tabs:pe,textarea:ue,theme:Y,toast:me,tooltip:fe};async function he(t){let n=process.cwd();e.intro("drivn add");let a=V(n);if(a||(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(r=>({label:r.name,hint:r.description,value:r.name})),required:true});e.isCancel(o)&&(e.cancel("Cancelled"),process.exit(0)),t=o;}let v=t.filter(o=>!R.find(r=>r.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 p=t.includes("theme"),g=t.filter(o=>o!=="theme"),u=new Set,b=new Set,h=o=>{if(u.has(o))return;let r=R.find(c=>c.name===o);r&&(r.dependencies.forEach(c=>h(c)),r.npmDependencies?.forEach(c=>b.add(c)),u.add(o));};g.forEach(h),p&&b.add("next-themes");let x=[...u].filter(o=>!g.includes(o));x.length&&e.log.info(`Required dependency: ${x.join(", ")}`);let l=a.typescript?"tsx":"jsx",N=join(n,a.paths.components);for(let o of u){let r=join(N,`${o}.${l}`);if(m(r)){let C=await e.confirm({message:`${o}.${l} exists. Overwrite?`,initialValue:false});if(e.isCancel(C)||!C){e.log.warn(`Skipped ${o}`);continue}}let c=S[o];c=c.replace(/@\/utils/g,`@/${a.paths.utils.replace(/^src\//,"")}`),d(r,c),e.log.success(`${o} \u2192 ${a.paths.components}/${o}.${l}`);}if(p){let o=join(N,`theme-provider.${l}`);if(m(o)){let c=await e.confirm({message:`theme-provider.${l} exists. Overwrite?`,initialValue:false});!e.isCancel(c)&&c?(d(o,S.theme),e.log.success(`theme-provider \u2192 ${a.paths.components}/theme-provider.${l}`)):e.log.warn("Skipped theme-provider");}else d(o,S.theme),e.log.success(`theme-provider \u2192 ${a.paths.components}/theme-provider.${l}`);if(a.paths.globals){let c=join(n,a.paths.globals);if(m(c)){let C=O(c);C.includes('[data-theme="dark"]')?e.log.warn("Theme tokens already exist in globals \u2014 skipped"):(d(c,C+M),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 o=join(n,a.paths.globals);if(m(o)){let r=O(o);r.includes(".rdp-root")?e.log.warn("Calendar tokens already exist in globals \u2014 skipped"):(d(o,r+ge),e.log.success(`Calendar tokens appended to ${i.cyan(a.paths.globals)}`));}}if(b.size){let o=P(n),r=[...b],c=e.spinner();c.start("Installing packages");try{execSync(y(o,r),{cwd:n,stdio:"ignore"}),c.stop("Packages installed");}catch{c.stop("Failed to install packages"),e.log.warn(`Run manually: ${y(o,r)}`);}}e.outro("Done.");}var ve={version:"1.2.0"};var T=new Command;T.name("drivn").description("Drivn \u2014 Modern UI components").version(ve.version);T.command("create").description("Initialize Drivn in your project").action(K);T.command("add [components...]").description("Add components to your project").action(he);T.parse();