drivn 1.1.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1514 -32
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {Command}from'commander';import*as e from'@clack/prompts';import i from'picocolors';import {join,dirname}from'path';import {execSync}from'child_process';import {existsSync,readFileSync,writeFileSync,mkdirSync}from'fs';var
|
|
2
|
+
import {Command}from'commander';import*as e from'@clack/prompts';import i from'picocolors';import {join,dirname}from'path';import {execSync}from'child_process';import {existsSync,readFileSync,writeFileSync,mkdirSync}from'fs';var 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")),b={...a.dependencies,...a.devDependencies},p="react";b.next&&(p="next");let g=existsSync(join(t,"src")),u=existsSync(join(t,"tsconfig.json"));return {framework:p,srcDir:g,typescript:u}}var V="drivn.config.json";function _(t){let n=join(t,V);return existsSync(n)?JSON.parse(readFileSync(n,"utf-8")):null}function $(t,n){let a=join(t,V);writeFileSync(a,JSON.stringify(n,null,2));}function Pe(t){existsSync(t)||mkdirSync(t,{recursive:true});}function d(t,n){Pe(dirname(t)),writeFileSync(t,n);}function M(t){return readFileSync(t,"utf-8")}function m(t){return existsSync(t)}function P(t){return existsSync(join(t,"pnpm-lock.yaml"))?"pnpm":"npm"}function y(t,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
|
-
`,
|
|
73
|
+
`,O=`
|
|
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
|
|
139
|
+
`;var Ee=`import { type ClassValue, clsx } from 'clsx'
|
|
140
140
|
import { twMerge } from 'tailwind-merge'
|
|
141
141
|
|
|
142
142
|
export function cn(...inputs: ClassValue[]) {
|
|
143
143
|
return twMerge(clsx(inputs))
|
|
144
144
|
}
|
|
145
|
-
`,
|
|
145
|
+
`,Le=["src/app/globals.css","src/styles/globals.css","src/styles/globals.scss","app/globals.css"];function Ie(t){for(let n of Le)if(m(join(t,n)))return n;return null}async function G(){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",b=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:b,defaultValue:b})},{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",v=join(t,p.utils,`cn.${u}`);m(v)||d(v,Ee);let h=Ie(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 K=`'use client'
|
|
146
146
|
|
|
147
147
|
import { ThemeProvider as NextThemesProvider } from 'next-themes'
|
|
148
148
|
|
|
@@ -161,7 +161,7 @@ export function ThemeProvider({
|
|
|
161
161
|
</NextThemesProvider>
|
|
162
162
|
)
|
|
163
163
|
}
|
|
164
|
-
`;var
|
|
164
|
+
`;var Y=`'use client'
|
|
165
165
|
|
|
166
166
|
import * as React from 'react'
|
|
167
167
|
import { ChevronDown } from 'lucide-react'
|
|
@@ -289,9 +289,11 @@ function useCtx() {
|
|
|
289
289
|
}
|
|
290
290
|
|
|
291
291
|
export const Accordion = Object.assign(AccordionRoot, {
|
|
292
|
-
Item,
|
|
292
|
+
Item,
|
|
293
|
+
Trigger,
|
|
294
|
+
Content
|
|
293
295
|
})
|
|
294
|
-
`;var
|
|
296
|
+
`;var W=`import * as React from 'react'
|
|
295
297
|
import { cn } from '@/utils/cn'
|
|
296
298
|
|
|
297
299
|
const styles = {
|
|
@@ -339,7 +341,7 @@ export function Alert({
|
|
|
339
341
|
</div>
|
|
340
342
|
)
|
|
341
343
|
}
|
|
342
|
-
`;var
|
|
344
|
+
`;var U=`import * as React from 'react'
|
|
343
345
|
import { cn } from '@/utils/cn'
|
|
344
346
|
|
|
345
347
|
const styles = {
|
|
@@ -383,7 +385,7 @@ export function Avatar({
|
|
|
383
385
|
</div>
|
|
384
386
|
)
|
|
385
387
|
}
|
|
386
|
-
`;var
|
|
388
|
+
`;var q=`import * as React from 'react'
|
|
387
389
|
import { cn } from '@/utils/cn'
|
|
388
390
|
|
|
389
391
|
const styles = {
|
|
@@ -413,7 +415,123 @@ export function Badge({ variant = 'default', className, children }: BadgeProps)
|
|
|
413
415
|
</span>
|
|
414
416
|
)
|
|
415
417
|
}
|
|
416
|
-
`;var
|
|
418
|
+
`;var X=`import * as React from 'react'
|
|
419
|
+
import { cn } from '@/utils/cn'
|
|
420
|
+
import { ChevronRight, MoreHorizontal } from 'lucide-react'
|
|
421
|
+
|
|
422
|
+
const styles = {
|
|
423
|
+
list: cn(
|
|
424
|
+
'flex items-center gap-1.5',
|
|
425
|
+
'flex-wrap text-sm text-muted-foreground'
|
|
426
|
+
),
|
|
427
|
+
link: cn(
|
|
428
|
+
'transition-colors hover:text-foreground',
|
|
429
|
+
'inline-flex items-center gap-1'
|
|
430
|
+
),
|
|
431
|
+
page: 'font-medium text-foreground',
|
|
432
|
+
separator: 'text-muted-foreground/60 [&>svg]:size-3.5',
|
|
433
|
+
ellipsis: cn(
|
|
434
|
+
'flex size-9 items-center justify-center',
|
|
435
|
+
'text-muted-foreground'
|
|
436
|
+
),
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
function BreadcrumbRoot({
|
|
440
|
+
separator,
|
|
441
|
+
className,
|
|
442
|
+
children,
|
|
443
|
+
}: {
|
|
444
|
+
separator?: React.ReactNode
|
|
445
|
+
className?: string
|
|
446
|
+
children: React.ReactNode
|
|
447
|
+
}) {
|
|
448
|
+
return (
|
|
449
|
+
<nav aria-label="Breadcrumb">
|
|
450
|
+
<ol className={cn(styles.list, className)}>
|
|
451
|
+
{React.Children.toArray(children).flatMap((child, i) => {
|
|
452
|
+
return !(React.isValidElement(child) &&
|
|
453
|
+
child.type === BreadcrumbSeparator) && i > 0 ? [
|
|
454
|
+
<BreadcrumbSeparator key={\`sep-\${i}\`}>
|
|
455
|
+
{separator}
|
|
456
|
+
</BreadcrumbSeparator>,
|
|
457
|
+
child,
|
|
458
|
+
] : [child]
|
|
459
|
+
})}
|
|
460
|
+
</ol>
|
|
461
|
+
</nav>
|
|
462
|
+
)
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
function Item({
|
|
466
|
+
href,
|
|
467
|
+
className,
|
|
468
|
+
children,
|
|
469
|
+
...props
|
|
470
|
+
}: React.AnchorHTMLAttributes<HTMLAnchorElement> & {
|
|
471
|
+
href: string
|
|
472
|
+
children: React.ReactNode
|
|
473
|
+
}) {
|
|
474
|
+
return (
|
|
475
|
+
<li>
|
|
476
|
+
<a
|
|
477
|
+
href={href}
|
|
478
|
+
className={cn(styles.link, className)}
|
|
479
|
+
{...props}
|
|
480
|
+
>
|
|
481
|
+
{children}
|
|
482
|
+
</a>
|
|
483
|
+
</li>
|
|
484
|
+
)
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
function Page({
|
|
488
|
+
className,
|
|
489
|
+
children,
|
|
490
|
+
}: {
|
|
491
|
+
className?: string
|
|
492
|
+
children: React.ReactNode
|
|
493
|
+
}) {
|
|
494
|
+
return (
|
|
495
|
+
<li aria-current="page">
|
|
496
|
+
<span className={cn(styles.page, className)}>
|
|
497
|
+
{children}
|
|
498
|
+
</span>
|
|
499
|
+
</li>
|
|
500
|
+
)
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
function BreadcrumbSeparator({
|
|
504
|
+
children,
|
|
505
|
+
}: {
|
|
506
|
+
children?: React.ReactNode
|
|
507
|
+
}) {
|
|
508
|
+
return (
|
|
509
|
+
<li role="presentation" aria-hidden="true">
|
|
510
|
+
<span className={styles.separator}>
|
|
511
|
+
{children ?? <ChevronRight />}
|
|
512
|
+
</span>
|
|
513
|
+
</li>
|
|
514
|
+
)
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
function Ellipsis() {
|
|
518
|
+
return (
|
|
519
|
+
<li>
|
|
520
|
+
<span className={styles.ellipsis}>
|
|
521
|
+
<MoreHorizontal className="size-4" />
|
|
522
|
+
<span className="sr-only">More pages</span>
|
|
523
|
+
</span>
|
|
524
|
+
</li>
|
|
525
|
+
)
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
export const Breadcrumb = Object.assign(BreadcrumbRoot, {
|
|
529
|
+
Item,
|
|
530
|
+
Page,
|
|
531
|
+
Separator: BreadcrumbSeparator,
|
|
532
|
+
Ellipsis,
|
|
533
|
+
})
|
|
534
|
+
`;var J=`import * as React from 'react'
|
|
417
535
|
import { Loader2 } from 'lucide-react'
|
|
418
536
|
import { cn } from '@/utils/cn'
|
|
419
537
|
|
|
@@ -492,8 +610,888 @@ export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(({
|
|
|
492
610
|
)
|
|
493
611
|
)
|
|
494
612
|
|
|
495
|
-
Button.displayName = 'Button'
|
|
496
|
-
`;var Q=`
|
|
613
|
+
Button.displayName = 'Button'
|
|
614
|
+
`;var Q=`'use client'
|
|
615
|
+
|
|
616
|
+
import * as React from 'react'
|
|
617
|
+
import {
|
|
618
|
+
DayPicker,
|
|
619
|
+
type DateRange,
|
|
620
|
+
type Locale,
|
|
621
|
+
type PropsBase,
|
|
622
|
+
type PropsSingle,
|
|
623
|
+
type PropsRange,
|
|
624
|
+
} from 'react-day-picker'
|
|
625
|
+
import { ChevronDown, ChevronLeft, ChevronRight } from 'lucide-react'
|
|
626
|
+
import { cn } from '@/utils/cn'
|
|
627
|
+
|
|
628
|
+
const styles = {
|
|
629
|
+
root: 'p-3 bg-card border border-border rounded-[10px] text-sm',
|
|
630
|
+
classNames: {
|
|
631
|
+
months: 'relative flex gap-4',
|
|
632
|
+
month: 'flex flex-col gap-4',
|
|
633
|
+
month_caption: 'flex items-center justify-center h-7',
|
|
634
|
+
caption_label: 'text-sm font-medium text-foreground',
|
|
635
|
+
nav: 'absolute inset-x-0 top-0 flex items-center justify-between h-7',
|
|
636
|
+
button_previous: cn(
|
|
637
|
+
'inline-flex items-center justify-center',
|
|
638
|
+
'w-7 h-7 rounded-md text-muted-foreground',
|
|
639
|
+
'hover:text-foreground hover:bg-accent',
|
|
640
|
+
'transition-colors cursor-pointer'
|
|
641
|
+
),
|
|
642
|
+
button_next: cn(
|
|
643
|
+
'inline-flex items-center justify-center',
|
|
644
|
+
'w-7 h-7 rounded-md text-muted-foreground',
|
|
645
|
+
'hover:text-foreground hover:bg-accent',
|
|
646
|
+
'transition-colors cursor-pointer'
|
|
647
|
+
),
|
|
648
|
+
month_grid: 'border-collapse border-spacing-0',
|
|
649
|
+
weekdays: '',
|
|
650
|
+
weekday: cn(
|
|
651
|
+
'w-8 pb-2 text-[0.8rem] font-medium',
|
|
652
|
+
'text-muted-foreground text-center'
|
|
653
|
+
),
|
|
654
|
+
week: '',
|
|
655
|
+
day: 'p-0 text-center',
|
|
656
|
+
day_button: cn(
|
|
657
|
+
'inline-flex items-center justify-center',
|
|
658
|
+
'w-8 h-8 rounded-md text-sm cursor-pointer',
|
|
659
|
+
'hover:bg-accent hover:text-accent-foreground',
|
|
660
|
+
'focus-visible:outline-none'
|
|
661
|
+
),
|
|
662
|
+
today: 'font-semibold text-primary',
|
|
663
|
+
selected: cn(
|
|
664
|
+
'[&>button]:bg-primary',
|
|
665
|
+
'[&>button]:text-primary-foreground',
|
|
666
|
+
'[&>button]:hover:bg-primary',
|
|
667
|
+
'[&>button]:hover:text-primary-foreground'
|
|
668
|
+
),
|
|
669
|
+
outside: 'text-muted-foreground/40',
|
|
670
|
+
disabled: 'text-muted-foreground/30 cursor-not-allowed',
|
|
671
|
+
range_middle: cn(
|
|
672
|
+
'bg-accent text-accent-foreground',
|
|
673
|
+
'hover:bg-accent hover:text-accent-foreground',
|
|
674
|
+
'rounded-none [&>button]:rounded-none'
|
|
675
|
+
),
|
|
676
|
+
chevron: 'w-4 h-4',
|
|
677
|
+
dropdown: cn(
|
|
678
|
+
'appearance-none bg-transparent text-sm',
|
|
679
|
+
'font-medium text-foreground cursor-pointer',
|
|
680
|
+
'border-none outline-none'
|
|
681
|
+
),
|
|
682
|
+
week_number: cn(
|
|
683
|
+
'w-8 text-[0.75rem]',
|
|
684
|
+
'text-muted-foreground/50 text-center font-normal'
|
|
685
|
+
),
|
|
686
|
+
hidden: 'invisible',
|
|
687
|
+
},
|
|
688
|
+
dropdownOverrides: {
|
|
689
|
+
dropdowns: 'flex items-center gap-2 justify-center',
|
|
690
|
+
dropdown_root: 'relative inline-flex items-center',
|
|
691
|
+
dropdown: 'absolute inset-0 opacity-0 cursor-pointer w-full z-10',
|
|
692
|
+
caption_label: cn(
|
|
693
|
+
'inline-flex items-center text-sm',
|
|
694
|
+
'font-medium text-foreground',
|
|
695
|
+
'pointer-events-none whitespace-nowrap'
|
|
696
|
+
),
|
|
697
|
+
chevron: 'w-3 h-3 ml-0.5 text-muted-foreground',
|
|
698
|
+
},
|
|
699
|
+
rangeActive: {
|
|
700
|
+
range_start: cn(
|
|
701
|
+
'bg-primary text-primary-foreground',
|
|
702
|
+
'rounded-l-md [&>button]:rounded-r-none'
|
|
703
|
+
),
|
|
704
|
+
range_end: cn(
|
|
705
|
+
'bg-primary text-primary-foreground',
|
|
706
|
+
'rounded-r-md [&>button]:rounded-l-none'
|
|
707
|
+
),
|
|
708
|
+
},
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
const variantConfig = {
|
|
712
|
+
default: {},
|
|
713
|
+
weekNumbers: { showWeekNumber: true },
|
|
714
|
+
dropdown: { captionLayout: 'dropdown' as const },
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
export type CalendarVariant = keyof typeof variantConfig
|
|
718
|
+
|
|
719
|
+
type CalendarProps = Omit<PropsBase, 'mode'> & Omit<PropsSingle, 'mode'> & { variant?: CalendarVariant; fromYear?: number; toYear?: number }
|
|
720
|
+
|
|
721
|
+
type RangeProps = Omit<PropsBase, 'mode'> & Omit<PropsRange, 'mode'>
|
|
722
|
+
|
|
723
|
+
function Chevron(props: { orientation?: 'left' | 'right' | 'up' | 'down'; size?: number; disabled?: boolean; className?: string }) {
|
|
724
|
+
const icons = { left: ChevronLeft, right: ChevronRight, down: ChevronDown, up: ChevronRight }
|
|
725
|
+
const Icon = icons[props.orientation ?? 'right']
|
|
726
|
+
return <Icon className={props.className} />
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
const currentYear = new Date().getFullYear()
|
|
730
|
+
|
|
731
|
+
function CalendarRoot({
|
|
732
|
+
variant = 'default',
|
|
733
|
+
fromYear = currentYear - 20,
|
|
734
|
+
toYear = currentYear + 20,
|
|
735
|
+
className,
|
|
736
|
+
classNames: userClassNames,
|
|
737
|
+
...props
|
|
738
|
+
}: CalendarProps) {
|
|
739
|
+
const dropdownRange = variant === 'dropdown' ? {
|
|
740
|
+
startMonth: new Date(fromYear, 0),
|
|
741
|
+
endMonth: new Date(toYear, 11),
|
|
742
|
+
} : {}
|
|
743
|
+
|
|
744
|
+
return (
|
|
745
|
+
<DayPicker
|
|
746
|
+
mode="single"
|
|
747
|
+
{...variantConfig[variant]}
|
|
748
|
+
{...dropdownRange}
|
|
749
|
+
classNames={{
|
|
750
|
+
...styles.classNames,
|
|
751
|
+
...(variant === 'dropdown' && styles.dropdownOverrides),
|
|
752
|
+
...userClassNames,
|
|
753
|
+
}}
|
|
754
|
+
components={{ Chevron }}
|
|
755
|
+
className={cn(styles.root, className)}
|
|
756
|
+
{...props}
|
|
757
|
+
/>
|
|
758
|
+
)
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
function Range({
|
|
762
|
+
className,
|
|
763
|
+
classNames: userClassNames,
|
|
764
|
+
selected,
|
|
765
|
+
...props
|
|
766
|
+
}: RangeProps) {
|
|
767
|
+
const hasRange = selected?.from && selected?.to && selected.from.getTime() !== selected.to.getTime()
|
|
768
|
+
|
|
769
|
+
return (
|
|
770
|
+
<DayPicker
|
|
771
|
+
mode="range"
|
|
772
|
+
selected={selected}
|
|
773
|
+
classNames={{
|
|
774
|
+
...styles.classNames,
|
|
775
|
+
...(hasRange && styles.rangeActive),
|
|
776
|
+
...userClassNames,
|
|
777
|
+
}}
|
|
778
|
+
components={{ Chevron }}
|
|
779
|
+
className={cn(styles.root, className)}
|
|
780
|
+
{...props}
|
|
781
|
+
/>
|
|
782
|
+
)
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
export { type DateRange, type Locale }
|
|
786
|
+
|
|
787
|
+
export const Calendar = Object.assign(CalendarRoot, {
|
|
788
|
+
Range
|
|
789
|
+
})
|
|
790
|
+
`;var Z=`'use client'
|
|
791
|
+
|
|
792
|
+
import * as React from 'react'
|
|
793
|
+
import { CalendarDays } from 'lucide-react'
|
|
794
|
+
import { cn } from '@/utils/cn'
|
|
795
|
+
import {
|
|
796
|
+
Calendar,
|
|
797
|
+
type CalendarVariant,
|
|
798
|
+
type DateRange,
|
|
799
|
+
type Locale,
|
|
800
|
+
} from '@/components/ui/calendar'
|
|
801
|
+
|
|
802
|
+
const styles = {
|
|
803
|
+
base: 'relative',
|
|
804
|
+
trigger: cn(
|
|
805
|
+
'flex items-center gap-2 w-full h-10 px-3',
|
|
806
|
+
'border border-input rounded-[10px] text-sm',
|
|
807
|
+
'text-foreground transition-colors cursor-pointer',
|
|
808
|
+
'focus:outline-none',
|
|
809
|
+
'disabled:opacity-50 disabled:cursor-default'
|
|
810
|
+
),
|
|
811
|
+
placeholder: 'text-muted-foreground',
|
|
812
|
+
icon: 'w-4 h-4 text-muted-foreground shrink-0',
|
|
813
|
+
text: 'flex-1 truncate text-left',
|
|
814
|
+
content: cn(
|
|
815
|
+
'absolute top-full left-0 mt-1 z-50',
|
|
816
|
+
'transition-[opacity,scale] duration-150 ease-out'
|
|
817
|
+
),
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
type FormatDateFn = (date: Date) => string
|
|
821
|
+
|
|
822
|
+
interface DatePickerBaseProps {
|
|
823
|
+
placeholder?: string
|
|
824
|
+
formatDate?: FormatDateFn
|
|
825
|
+
disabled?: boolean
|
|
826
|
+
locale?: Partial<Locale>
|
|
827
|
+
defaultMonth?: Date
|
|
828
|
+
className?: string
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
interface DatePickerProps extends DatePickerBaseProps {
|
|
832
|
+
selected?: Date
|
|
833
|
+
onSelect?: (date: Date | undefined) => void
|
|
834
|
+
variant?: CalendarVariant
|
|
835
|
+
fromYear?: number
|
|
836
|
+
toYear?: number
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
interface DatePickerRangeProps extends DatePickerBaseProps {
|
|
840
|
+
selected?: DateRange
|
|
841
|
+
onSelect?: (range: DateRange | undefined) => void
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
function formatRangeLabel(
|
|
845
|
+
range: DateRange,
|
|
846
|
+
fmt: FormatDateFn
|
|
847
|
+
): string {
|
|
848
|
+
if (!range.from) return ''
|
|
849
|
+
if (!range.to) return fmt(range.from)
|
|
850
|
+
return \\\`\\\${fmt(range.from)} \u2013 \\\${fmt(range.to)}\\\`
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
function DatePickerRoot({
|
|
854
|
+
selected,
|
|
855
|
+
onSelect,
|
|
856
|
+
placeholder = 'Pick a date',
|
|
857
|
+
formatDate,
|
|
858
|
+
disabled = false,
|
|
859
|
+
locale,
|
|
860
|
+
variant = 'default',
|
|
861
|
+
fromYear,
|
|
862
|
+
toYear,
|
|
863
|
+
defaultMonth,
|
|
864
|
+
className,
|
|
865
|
+
}: DatePickerProps) {
|
|
866
|
+
const fmt = formatDate ?? ((d: Date) =>
|
|
867
|
+
d.toLocaleDateString(locale?.code ?? 'en-US', { month: 'short', day: 'numeric', year: 'numeric' }))
|
|
868
|
+
const [open, setOpen] = React.useState(false)
|
|
869
|
+
const ref = React.useRef<HTMLDivElement>(null)
|
|
870
|
+
|
|
871
|
+
React.useEffect(() => {
|
|
872
|
+
if (!open) return
|
|
873
|
+
const onMouseDown = (e: MouseEvent) => {
|
|
874
|
+
if (!ref.current?.contains(e.target as Node)) {
|
|
875
|
+
setOpen(false)
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
document.addEventListener('mousedown', onMouseDown)
|
|
879
|
+
return () => {
|
|
880
|
+
document.removeEventListener('mousedown', onMouseDown)
|
|
881
|
+
}
|
|
882
|
+
}, [open])
|
|
883
|
+
|
|
884
|
+
React.useEffect(() => {
|
|
885
|
+
if (!open) return
|
|
886
|
+
const onKeyDown = (e: KeyboardEvent) => {
|
|
887
|
+
if (e.key === 'Escape') setOpen(false)
|
|
888
|
+
}
|
|
889
|
+
document.addEventListener('keydown', onKeyDown)
|
|
890
|
+
return () => {
|
|
891
|
+
document.removeEventListener('keydown', onKeyDown)
|
|
892
|
+
}
|
|
893
|
+
}, [open])
|
|
894
|
+
|
|
895
|
+
const handleSelect = React.useCallback(
|
|
896
|
+
(date: Date | undefined) => {
|
|
897
|
+
onSelect?.(date)
|
|
898
|
+
setOpen(false)
|
|
899
|
+
},
|
|
900
|
+
[onSelect]
|
|
901
|
+
)
|
|
902
|
+
|
|
903
|
+
return (
|
|
904
|
+
<div ref={ref} className={cn(styles.base, className)}>
|
|
905
|
+
<button
|
|
906
|
+
type="button"
|
|
907
|
+
className={styles.trigger}
|
|
908
|
+
disabled={disabled}
|
|
909
|
+
onClick={() => setOpen((v) => !v)}
|
|
910
|
+
>
|
|
911
|
+
<CalendarDays className={styles.icon} />
|
|
912
|
+
<span className={cn(styles.text, !selected && styles.placeholder)}>
|
|
913
|
+
{selected ? fmt(selected) : placeholder}
|
|
914
|
+
</span>
|
|
915
|
+
</button>
|
|
916
|
+
<div className={cn(styles.content, open ? 'opacity-100 scale-100' : 'opacity-0 scale-95 pointer-events-none')}>
|
|
917
|
+
<Calendar
|
|
918
|
+
variant={variant}
|
|
919
|
+
locale={locale}
|
|
920
|
+
selected={selected}
|
|
921
|
+
onSelect={handleSelect}
|
|
922
|
+
defaultMonth={defaultMonth ?? selected}
|
|
923
|
+
{...(fromYear !== undefined && { fromYear })}
|
|
924
|
+
{...(toYear !== undefined && { toYear })}
|
|
925
|
+
/>
|
|
926
|
+
</div>
|
|
927
|
+
</div>
|
|
928
|
+
)
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
function Range({
|
|
932
|
+
selected,
|
|
933
|
+
onSelect,
|
|
934
|
+
placeholder = 'Pick a date range',
|
|
935
|
+
formatDate,
|
|
936
|
+
disabled = false,
|
|
937
|
+
locale,
|
|
938
|
+
defaultMonth,
|
|
939
|
+
className,
|
|
940
|
+
}: DatePickerRangeProps) {
|
|
941
|
+
const fmt = formatDate ?? ((d: Date) =>
|
|
942
|
+
d.toLocaleDateString(locale?.code ?? 'en-US', { month: 'short', day: 'numeric', year: 'numeric' }))
|
|
943
|
+
const [open, setOpen] = React.useState(false)
|
|
944
|
+
const ref = React.useRef<HTMLDivElement>(null)
|
|
945
|
+
|
|
946
|
+
React.useEffect(() => {
|
|
947
|
+
if (!open) return
|
|
948
|
+
const onMouseDown = (e: MouseEvent) => {
|
|
949
|
+
if (!ref.current?.contains(e.target as Node)) {
|
|
950
|
+
setOpen(false)
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
document.addEventListener('mousedown', onMouseDown)
|
|
954
|
+
return () => {
|
|
955
|
+
document.removeEventListener('mousedown', onMouseDown)
|
|
956
|
+
}
|
|
957
|
+
}, [open])
|
|
958
|
+
|
|
959
|
+
React.useEffect(() => {
|
|
960
|
+
if (!open) return
|
|
961
|
+
const onKeyDown = (e: KeyboardEvent) => {
|
|
962
|
+
if (e.key === 'Escape') setOpen(false)
|
|
963
|
+
}
|
|
964
|
+
document.addEventListener('keydown', onKeyDown)
|
|
965
|
+
return () => {
|
|
966
|
+
document.removeEventListener('keydown', onKeyDown)
|
|
967
|
+
}
|
|
968
|
+
}, [open])
|
|
969
|
+
|
|
970
|
+
const handleSelect = React.useCallback(
|
|
971
|
+
(range: DateRange | undefined) => {
|
|
972
|
+
onSelect?.(range)
|
|
973
|
+
const complete = range?.from && range?.to
|
|
974
|
+
&& range.from.getTime() !== range.to.getTime()
|
|
975
|
+
if (complete) setOpen(false)
|
|
976
|
+
},
|
|
977
|
+
[onSelect]
|
|
978
|
+
)
|
|
979
|
+
|
|
980
|
+
const label = selected
|
|
981
|
+
? formatRangeLabel(selected, fmt)
|
|
982
|
+
: undefined
|
|
983
|
+
|
|
984
|
+
return (
|
|
985
|
+
<div ref={ref} className={cn(styles.base, className)}>
|
|
986
|
+
<button
|
|
987
|
+
type="button"
|
|
988
|
+
className={styles.trigger}
|
|
989
|
+
disabled={disabled}
|
|
990
|
+
onClick={() => setOpen((v) => !v)}
|
|
991
|
+
>
|
|
992
|
+
<CalendarDays className={styles.icon} />
|
|
993
|
+
<span className={cn(styles.text, !label && styles.placeholder)}>
|
|
994
|
+
{label ?? placeholder}
|
|
995
|
+
</span>
|
|
996
|
+
</button>
|
|
997
|
+
<div className={cn(styles.content, open ? 'opacity-100 scale-100' : 'opacity-0 scale-95 pointer-events-none')}>
|
|
998
|
+
<Calendar.Range
|
|
999
|
+
locale={locale}
|
|
1000
|
+
selected={selected}
|
|
1001
|
+
onSelect={handleSelect}
|
|
1002
|
+
defaultMonth={defaultMonth ?? selected?.from}
|
|
1003
|
+
/>
|
|
1004
|
+
</div>
|
|
1005
|
+
</div>
|
|
1006
|
+
)
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
export { type DateRange, type Locale }
|
|
1010
|
+
|
|
1011
|
+
export const DatePicker = Object.assign(DatePickerRoot, {
|
|
1012
|
+
Range,
|
|
1013
|
+
})
|
|
1014
|
+
`;var ee=`'use client'
|
|
1015
|
+
|
|
1016
|
+
import * as React from 'react'
|
|
1017
|
+
import { Command as CommandPrimitive } from 'cmdk'
|
|
1018
|
+
import { Search } from 'lucide-react'
|
|
1019
|
+
import { cn } from '@/utils/cn'
|
|
1020
|
+
import { Dialog } from '@/components/ui/dialog'
|
|
1021
|
+
|
|
1022
|
+
const styles = {
|
|
1023
|
+
root: cn(
|
|
1024
|
+
'flex flex-col overflow-hidden',
|
|
1025
|
+
'bg-card border border-border rounded-[10px]'
|
|
1026
|
+
),
|
|
1027
|
+
input: {
|
|
1028
|
+
wrapper: cn(
|
|
1029
|
+
'flex items-center gap-2 px-3',
|
|
1030
|
+
'border-b border-border'
|
|
1031
|
+
),
|
|
1032
|
+
icon: 'w-4 h-4 shrink-0 text-muted-foreground',
|
|
1033
|
+
field: cn(
|
|
1034
|
+
'flex h-10 w-full bg-transparent py-2',
|
|
1035
|
+
'text-sm text-foreground outline-none',
|
|
1036
|
+
'placeholder:text-muted-foreground',
|
|
1037
|
+
'disabled:cursor-not-allowed disabled:opacity-50'
|
|
1038
|
+
),
|
|
1039
|
+
},
|
|
1040
|
+
list: cn(
|
|
1041
|
+
'h-[300px] overflow-y-auto overflow-x-hidden p-1',
|
|
1042
|
+
'[&_[cmdk-list-sizer]]:space-y-1'
|
|
1043
|
+
),
|
|
1044
|
+
empty: cn(
|
|
1045
|
+
'py-6 text-center text-sm',
|
|
1046
|
+
'text-muted-foreground'
|
|
1047
|
+
),
|
|
1048
|
+
loading: cn(
|
|
1049
|
+
'py-6 text-center text-sm',
|
|
1050
|
+
'text-muted-foreground'
|
|
1051
|
+
),
|
|
1052
|
+
group: cn(
|
|
1053
|
+
'overflow-hidden',
|
|
1054
|
+
'[&_[cmdk-group-heading]]:px-2',
|
|
1055
|
+
'[&_[cmdk-group-heading]]:py-1.5',
|
|
1056
|
+
'[&_[cmdk-group-heading]]:text-xs',
|
|
1057
|
+
'[&_[cmdk-group-heading]]:font-medium',
|
|
1058
|
+
'[&_[cmdk-group-heading]]:text-muted-foreground'
|
|
1059
|
+
),
|
|
1060
|
+
item: cn(
|
|
1061
|
+
'relative flex items-center gap-2 px-2 py-1.5',
|
|
1062
|
+
'text-sm rounded-lg cursor-default select-none',
|
|
1063
|
+
'data-[selected=true]:bg-accent',
|
|
1064
|
+
'data-[selected=true]:text-accent-foreground',
|
|
1065
|
+
'data-[disabled=true]:pointer-events-none',
|
|
1066
|
+
'data-[disabled=true]:opacity-50'
|
|
1067
|
+
),
|
|
1068
|
+
separator: '-mx-1 h-px bg-border',
|
|
1069
|
+
shortcut: cn(
|
|
1070
|
+
'ml-auto text-xs tracking-widest',
|
|
1071
|
+
'text-muted-foreground'
|
|
1072
|
+
),
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
function CommandRoot({
|
|
1076
|
+
className,
|
|
1077
|
+
...props
|
|
1078
|
+
}: React.ComponentProps<typeof CommandPrimitive>) {
|
|
1079
|
+
return (
|
|
1080
|
+
<CommandPrimitive
|
|
1081
|
+
className={cn(styles.root, className)}
|
|
1082
|
+
{...props}
|
|
1083
|
+
/>
|
|
1084
|
+
)
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
function Input({
|
|
1088
|
+
className,
|
|
1089
|
+
...props
|
|
1090
|
+
}: React.ComponentProps<typeof CommandPrimitive.Input>) {
|
|
1091
|
+
return (
|
|
1092
|
+
<div className={styles.input.wrapper}>
|
|
1093
|
+
<Search className={styles.input.icon} />
|
|
1094
|
+
<CommandPrimitive.Input
|
|
1095
|
+
className={cn(styles.input.field, className)}
|
|
1096
|
+
{...props}
|
|
1097
|
+
/>
|
|
1098
|
+
</div>
|
|
1099
|
+
)
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
function List({
|
|
1103
|
+
className,
|
|
1104
|
+
...props
|
|
1105
|
+
}: React.ComponentProps<typeof CommandPrimitive.List>) {
|
|
1106
|
+
return (
|
|
1107
|
+
<CommandPrimitive.List
|
|
1108
|
+
className={cn(styles.list, className)}
|
|
1109
|
+
{...props}
|
|
1110
|
+
/>
|
|
1111
|
+
)
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
function Empty({
|
|
1115
|
+
className,
|
|
1116
|
+
children,
|
|
1117
|
+
...props
|
|
1118
|
+
}: React.ComponentProps<typeof CommandPrimitive.Empty>) {
|
|
1119
|
+
return (
|
|
1120
|
+
<CommandPrimitive.Empty
|
|
1121
|
+
className={cn(styles.empty, className)}
|
|
1122
|
+
{...props}
|
|
1123
|
+
>
|
|
1124
|
+
{children ?? 'No results found.'}
|
|
1125
|
+
</CommandPrimitive.Empty>
|
|
1126
|
+
)
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
function Group({
|
|
1130
|
+
className,
|
|
1131
|
+
...props
|
|
1132
|
+
}: React.ComponentProps<typeof CommandPrimitive.Group>) {
|
|
1133
|
+
return (
|
|
1134
|
+
<CommandPrimitive.Group
|
|
1135
|
+
className={cn(styles.group, className)}
|
|
1136
|
+
{...props}
|
|
1137
|
+
/>
|
|
1138
|
+
)
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
function Item({
|
|
1142
|
+
className,
|
|
1143
|
+
...props
|
|
1144
|
+
}: React.ComponentProps<typeof CommandPrimitive.Item>) {
|
|
1145
|
+
return (
|
|
1146
|
+
<CommandPrimitive.Item
|
|
1147
|
+
className={cn(styles.item, className)}
|
|
1148
|
+
{...props}
|
|
1149
|
+
/>
|
|
1150
|
+
)
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
function Separator({
|
|
1154
|
+
className,
|
|
1155
|
+
...props
|
|
1156
|
+
}: React.ComponentProps<typeof CommandPrimitive.Separator>) {
|
|
1157
|
+
return (
|
|
1158
|
+
<CommandPrimitive.Separator
|
|
1159
|
+
className={cn(styles.separator, className)}
|
|
1160
|
+
{...props}
|
|
1161
|
+
/>
|
|
1162
|
+
)
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
function Loading({
|
|
1166
|
+
className,
|
|
1167
|
+
...props
|
|
1168
|
+
}: React.ComponentProps<typeof CommandPrimitive.Loading>) {
|
|
1169
|
+
return (
|
|
1170
|
+
<CommandPrimitive.Loading
|
|
1171
|
+
className={cn(styles.loading, className)}
|
|
1172
|
+
{...props}
|
|
1173
|
+
/>
|
|
1174
|
+
)
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
function Shortcut({
|
|
1178
|
+
className,
|
|
1179
|
+
...props
|
|
1180
|
+
}: React.HTMLAttributes<HTMLElement>) {
|
|
1181
|
+
return (
|
|
1182
|
+
<kbd
|
|
1183
|
+
className={cn(styles.shortcut, className)}
|
|
1184
|
+
{...props}
|
|
1185
|
+
/>
|
|
1186
|
+
)
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
function CommandDialog({
|
|
1190
|
+
open,
|
|
1191
|
+
onOpenChange,
|
|
1192
|
+
label,
|
|
1193
|
+
className,
|
|
1194
|
+
children,
|
|
1195
|
+
}: {
|
|
1196
|
+
open: boolean
|
|
1197
|
+
onOpenChange: (open: boolean) => void
|
|
1198
|
+
label?: string
|
|
1199
|
+
className?: string
|
|
1200
|
+
children: React.ReactNode
|
|
1201
|
+
}) {
|
|
1202
|
+
React.useEffect(() => {
|
|
1203
|
+
const onKeyDown = (e: KeyboardEvent) => {
|
|
1204
|
+
if (e.key === 'k' && (e.metaKey || e.ctrlKey)) {
|
|
1205
|
+
e.preventDefault()
|
|
1206
|
+
onOpenChange(!open)
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
document.addEventListener('keydown', onKeyDown)
|
|
1210
|
+
return () => {
|
|
1211
|
+
document.removeEventListener('keydown', onKeyDown)
|
|
1212
|
+
}
|
|
1213
|
+
}, [open, onOpenChange])
|
|
1214
|
+
|
|
1215
|
+
return (
|
|
1216
|
+
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
1217
|
+
<Dialog.Content
|
|
1218
|
+
className={cn(
|
|
1219
|
+
'p-0 max-w-lg rounded-[10px]',
|
|
1220
|
+
className
|
|
1221
|
+
)}
|
|
1222
|
+
>
|
|
1223
|
+
<CommandPrimitive
|
|
1224
|
+
label={label}
|
|
1225
|
+
className="flex flex-col overflow-hidden"
|
|
1226
|
+
>
|
|
1227
|
+
{children}
|
|
1228
|
+
</CommandPrimitive>
|
|
1229
|
+
</Dialog.Content>
|
|
1230
|
+
</Dialog>
|
|
1231
|
+
)
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
export const Command = Object.assign(CommandRoot, {
|
|
1235
|
+
Input,
|
|
1236
|
+
List,
|
|
1237
|
+
Empty,
|
|
1238
|
+
Group,
|
|
1239
|
+
Item,
|
|
1240
|
+
Separator,
|
|
1241
|
+
Loading,
|
|
1242
|
+
Shortcut,
|
|
1243
|
+
Dialog: CommandDialog,
|
|
1244
|
+
})
|
|
1245
|
+
`;var te=`'use client'
|
|
1246
|
+
|
|
1247
|
+
import * as React from 'react'
|
|
1248
|
+
import useEmblaCarousel, { type UseEmblaCarouselType } from 'embla-carousel-react'
|
|
1249
|
+
import { ChevronLeft, ChevronRight } from 'lucide-react'
|
|
1250
|
+
import { cn } from '@/utils/cn'
|
|
1251
|
+
import { Button } from '@/components/ui/button'
|
|
1252
|
+
|
|
1253
|
+
type CarouselApi = UseEmblaCarouselType[1]
|
|
1254
|
+
type CarouselOptions = Parameters<typeof useEmblaCarousel>[0]
|
|
1255
|
+
type CarouselPlugins = Parameters<typeof useEmblaCarousel>[1]
|
|
1256
|
+
|
|
1257
|
+
const styles = {
|
|
1258
|
+
root: 'relative focus-visible:outline-none',
|
|
1259
|
+
content: {
|
|
1260
|
+
viewport: 'overflow-hidden',
|
|
1261
|
+
container: 'flex',
|
|
1262
|
+
horizontal: '-ml-4',
|
|
1263
|
+
vertical: '-mt-4 flex-col h-full',
|
|
1264
|
+
},
|
|
1265
|
+
item: {
|
|
1266
|
+
base: 'min-w-0 shrink-0 grow-0 basis-full',
|
|
1267
|
+
horizontal: 'pl-4',
|
|
1268
|
+
vertical: 'pt-4',
|
|
1269
|
+
},
|
|
1270
|
+
arrow: cn(
|
|
1271
|
+
'absolute top-1/2 -translate-y-1/2',
|
|
1272
|
+
'w-8 px-0 bg-card/80 backdrop-blur-sm'
|
|
1273
|
+
),
|
|
1274
|
+
dots: {
|
|
1275
|
+
wrapper: 'flex justify-center gap-1.5 mt-3',
|
|
1276
|
+
dot: cn(
|
|
1277
|
+
'w-2 h-2 rounded-full transition-colors',
|
|
1278
|
+
'bg-border cursor-pointer'
|
|
1279
|
+
),
|
|
1280
|
+
active: 'bg-foreground',
|
|
1281
|
+
},
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
interface CarouselCtx {
|
|
1285
|
+
emblaRef: UseEmblaCarouselType[0]
|
|
1286
|
+
api: CarouselApi
|
|
1287
|
+
canScrollPrev: boolean
|
|
1288
|
+
canScrollNext: boolean
|
|
1289
|
+
selectedIndex: number
|
|
1290
|
+
scrollSnaps: number[]
|
|
1291
|
+
orientation: 'horizontal' | 'vertical'
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
interface CarouselRootProps
|
|
1295
|
+
extends React.HTMLAttributes<HTMLDivElement> {
|
|
1296
|
+
opts?: CarouselOptions
|
|
1297
|
+
plugins?: CarouselPlugins
|
|
1298
|
+
orientation?: 'horizontal' | 'vertical'
|
|
1299
|
+
setApi?: (api: CarouselApi) => void
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1302
|
+
function CarouselRoot({
|
|
1303
|
+
opts,
|
|
1304
|
+
plugins,
|
|
1305
|
+
orientation = 'horizontal',
|
|
1306
|
+
setApi,
|
|
1307
|
+
className,
|
|
1308
|
+
children,
|
|
1309
|
+
...props
|
|
1310
|
+
}: CarouselRootProps) {
|
|
1311
|
+
const [emblaRef, api] = useEmblaCarousel({ ...opts, axis: orientation === 'vertical' ? 'y' : 'x' }, plugins)
|
|
1312
|
+
const [canScrollPrev, setCanScrollPrev] = React.useState(false)
|
|
1313
|
+
const [canScrollNext, setCanScrollNext] = React.useState(false)
|
|
1314
|
+
const [selectedIndex, setSelectedIndex] = React.useState(0)
|
|
1315
|
+
const [scrollSnaps, setScrollSnaps] = React.useState<number[]>([])
|
|
1316
|
+
|
|
1317
|
+
const onSelect = React.useCallback((emblaApi: NonNullable<CarouselApi>) => {
|
|
1318
|
+
setCanScrollPrev(emblaApi.canScrollPrev())
|
|
1319
|
+
setCanScrollNext(emblaApi.canScrollNext())
|
|
1320
|
+
setSelectedIndex(emblaApi.selectedScrollSnap())
|
|
1321
|
+
}, [])
|
|
1322
|
+
|
|
1323
|
+
React.useEffect(() => {
|
|
1324
|
+
if (!api) return
|
|
1325
|
+
setScrollSnaps(api.scrollSnapList())
|
|
1326
|
+
onSelect(api)
|
|
1327
|
+
api.on('reInit', onSelect)
|
|
1328
|
+
api.on('select', onSelect)
|
|
1329
|
+
return () => {
|
|
1330
|
+
api.off('reInit', onSelect)
|
|
1331
|
+
api.off('select', onSelect)
|
|
1332
|
+
}
|
|
1333
|
+
}, [api, onSelect])
|
|
1334
|
+
|
|
1335
|
+
React.useEffect(() => {
|
|
1336
|
+
if (setApi && api) setApi(api)
|
|
1337
|
+
}, [api, setApi])
|
|
1338
|
+
|
|
1339
|
+
const handleKeyDown = React.useCallback((e: React.KeyboardEvent) => {
|
|
1340
|
+
if (!api) return
|
|
1341
|
+
if (e.key === 'ArrowLeft') {
|
|
1342
|
+
e.preventDefault()
|
|
1343
|
+
api.scrollPrev()
|
|
1344
|
+
} else if (e.key === 'ArrowRight') {
|
|
1345
|
+
e.preventDefault()
|
|
1346
|
+
api.scrollNext()
|
|
1347
|
+
}
|
|
1348
|
+
}, [api])
|
|
1349
|
+
|
|
1350
|
+
return (
|
|
1351
|
+
<Ctx.Provider
|
|
1352
|
+
value={{
|
|
1353
|
+
emblaRef,
|
|
1354
|
+
api,
|
|
1355
|
+
canScrollPrev,
|
|
1356
|
+
canScrollNext,
|
|
1357
|
+
selectedIndex,
|
|
1358
|
+
scrollSnaps,
|
|
1359
|
+
orientation,
|
|
1360
|
+
}}
|
|
1361
|
+
>
|
|
1362
|
+
<div
|
|
1363
|
+
role="region"
|
|
1364
|
+
aria-roledescription="carousel"
|
|
1365
|
+
tabIndex={0}
|
|
1366
|
+
onKeyDown={handleKeyDown}
|
|
1367
|
+
className={cn(styles.root, className)}
|
|
1368
|
+
{...props}
|
|
1369
|
+
>
|
|
1370
|
+
{children}
|
|
1371
|
+
</div>
|
|
1372
|
+
</Ctx.Provider>
|
|
1373
|
+
)
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
function Content({
|
|
1377
|
+
className,
|
|
1378
|
+
children,
|
|
1379
|
+
}: {
|
|
1380
|
+
className?: string
|
|
1381
|
+
children: React.ReactNode
|
|
1382
|
+
}) {
|
|
1383
|
+
const { emblaRef, orientation } = useCarousel()
|
|
1384
|
+
return (
|
|
1385
|
+
<div className={cn(styles.content.viewport, className)} ref={emblaRef}>
|
|
1386
|
+
<div className={cn(styles.content.container, orientation === 'vertical' ? styles.content.vertical : styles.content.horizontal)}>
|
|
1387
|
+
{children}
|
|
1388
|
+
</div>
|
|
1389
|
+
</div>
|
|
1390
|
+
)
|
|
1391
|
+
}
|
|
1392
|
+
|
|
1393
|
+
function Item({
|
|
1394
|
+
className,
|
|
1395
|
+
children,
|
|
1396
|
+
}: {
|
|
1397
|
+
className?: string
|
|
1398
|
+
children: React.ReactNode
|
|
1399
|
+
}) {
|
|
1400
|
+
const { orientation } = useCarousel()
|
|
1401
|
+
return (
|
|
1402
|
+
<div
|
|
1403
|
+
role="group"
|
|
1404
|
+
aria-roledescription="slide"
|
|
1405
|
+
className={cn(styles.item.base, orientation === 'vertical' ? styles.item.vertical : styles.item.horizontal, className)}
|
|
1406
|
+
>
|
|
1407
|
+
{children}
|
|
1408
|
+
</div>
|
|
1409
|
+
)
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1412
|
+
function Previous({
|
|
1413
|
+
className,
|
|
1414
|
+
variant = 'secondary',
|
|
1415
|
+
size = 'sm',
|
|
1416
|
+
...props
|
|
1417
|
+
}: React.ComponentProps<typeof Button>) {
|
|
1418
|
+
const { api, canScrollPrev } = useCarousel()
|
|
1419
|
+
return (
|
|
1420
|
+
<Button
|
|
1421
|
+
variant={variant}
|
|
1422
|
+
size={size}
|
|
1423
|
+
aria-label="Previous slide"
|
|
1424
|
+
className={cn(styles.arrow, '-left-12', className)}
|
|
1425
|
+
disabled={!canScrollPrev}
|
|
1426
|
+
onClick={() => api?.scrollPrev()}
|
|
1427
|
+
{...props}
|
|
1428
|
+
>
|
|
1429
|
+
<ChevronLeft className="w-4 h-4" />
|
|
1430
|
+
</Button>
|
|
1431
|
+
)
|
|
1432
|
+
}
|
|
1433
|
+
|
|
1434
|
+
function Next({
|
|
1435
|
+
className,
|
|
1436
|
+
variant = 'secondary',
|
|
1437
|
+
size = 'sm',
|
|
1438
|
+
...props
|
|
1439
|
+
}: React.ComponentProps<typeof Button>) {
|
|
1440
|
+
const { api, canScrollNext } = useCarousel()
|
|
1441
|
+
return (
|
|
1442
|
+
<Button
|
|
1443
|
+
variant={variant}
|
|
1444
|
+
size={size}
|
|
1445
|
+
aria-label="Next slide"
|
|
1446
|
+
className={cn(styles.arrow, '-right-12', className)}
|
|
1447
|
+
disabled={!canScrollNext}
|
|
1448
|
+
onClick={() => api?.scrollNext()}
|
|
1449
|
+
{...props}
|
|
1450
|
+
>
|
|
1451
|
+
<ChevronRight className="w-4 h-4" />
|
|
1452
|
+
</Button>
|
|
1453
|
+
)
|
|
1454
|
+
}
|
|
1455
|
+
|
|
1456
|
+
function Dots({
|
|
1457
|
+
className,
|
|
1458
|
+
}: {
|
|
1459
|
+
className?: string
|
|
1460
|
+
}) {
|
|
1461
|
+
const { api, scrollSnaps, selectedIndex } = useCarousel()
|
|
1462
|
+
return (
|
|
1463
|
+
<div className={cn(styles.dots.wrapper, className)}>
|
|
1464
|
+
{scrollSnaps.map((_, i) => (
|
|
1465
|
+
<button
|
|
1466
|
+
key={i}
|
|
1467
|
+
type="button"
|
|
1468
|
+
aria-label={\`Go to slide \${i + 1}\`}
|
|
1469
|
+
className={cn(styles.dots.dot, i === selectedIndex && styles.dots.active)}
|
|
1470
|
+
onClick={() => api?.scrollTo(i)}
|
|
1471
|
+
/>
|
|
1472
|
+
))}
|
|
1473
|
+
</div>
|
|
1474
|
+
)
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1477
|
+
const Ctx = React.createContext<CarouselCtx | null>(null)
|
|
1478
|
+
|
|
1479
|
+
function useCarousel() {
|
|
1480
|
+
const ctx = React.useContext(Ctx)
|
|
1481
|
+
if (!ctx) throw new Error('Carousel.* used outside <Carousel>')
|
|
1482
|
+
return ctx
|
|
1483
|
+
}
|
|
1484
|
+
|
|
1485
|
+
export type { CarouselApi }
|
|
1486
|
+
|
|
1487
|
+
export const Carousel = Object.assign(CarouselRoot, {
|
|
1488
|
+
Content,
|
|
1489
|
+
Item,
|
|
1490
|
+
Previous,
|
|
1491
|
+
Next,
|
|
1492
|
+
Dots
|
|
1493
|
+
})
|
|
1494
|
+
`;var oe=`import * as React from 'react'
|
|
497
1495
|
import { cn } from '@/utils/cn'
|
|
498
1496
|
|
|
499
1497
|
const styles = {
|
|
@@ -558,9 +1556,9 @@ function Info({
|
|
|
558
1556
|
|
|
559
1557
|
export const Card = Object.assign(CardRoot, {
|
|
560
1558
|
Preview,
|
|
561
|
-
Info
|
|
1559
|
+
Info
|
|
562
1560
|
})
|
|
563
|
-
`;var
|
|
1561
|
+
`;var ne=`'use client'
|
|
564
1562
|
|
|
565
1563
|
import * as React from 'react'
|
|
566
1564
|
import { Check } from 'lucide-react'
|
|
@@ -623,7 +1621,7 @@ export const Checkbox = React.forwardRef<HTMLInputElement, CheckboxProps>(({
|
|
|
623
1621
|
)
|
|
624
1622
|
|
|
625
1623
|
Checkbox.displayName = 'Checkbox'
|
|
626
|
-
`;var
|
|
1624
|
+
`;var re=`'use client'
|
|
627
1625
|
|
|
628
1626
|
import * as React from 'react'
|
|
629
1627
|
import { X } from 'lucide-react'
|
|
@@ -780,9 +1778,9 @@ function useDialog() {
|
|
|
780
1778
|
export const Dialog = Object.assign(DialogRoot, {
|
|
781
1779
|
Trigger,
|
|
782
1780
|
Content,
|
|
783
|
-
Close
|
|
1781
|
+
Close
|
|
784
1782
|
})
|
|
785
|
-
`;var
|
|
1783
|
+
`;var se=`'use client'
|
|
786
1784
|
|
|
787
1785
|
import * as React from 'react'
|
|
788
1786
|
import { cn } from '@/utils/cn'
|
|
@@ -978,9 +1976,9 @@ export const Dropdown = Object.assign(DropdownRoot, {
|
|
|
978
1976
|
Item,
|
|
979
1977
|
Group,
|
|
980
1978
|
Label,
|
|
981
|
-
Separator: DropdownSeparator
|
|
1979
|
+
Separator: DropdownSeparator
|
|
982
1980
|
})
|
|
983
|
-
`;var
|
|
1981
|
+
`;var ae=`import * as React from 'react'
|
|
984
1982
|
import { cn } from '@/utils/cn'
|
|
985
1983
|
|
|
986
1984
|
const styles = {
|
|
@@ -1003,7 +2001,157 @@ export const Input = React.forwardRef<HTMLInputElement, InputProps>(({
|
|
|
1003
2001
|
)
|
|
1004
2002
|
|
|
1005
2003
|
Input.displayName = 'Input'
|
|
1006
|
-
`;var
|
|
2004
|
+
`;var ce=`import * as React from 'react'
|
|
2005
|
+
import { cn } from '@/utils/cn'
|
|
2006
|
+
|
|
2007
|
+
export function Label({
|
|
2008
|
+
className,
|
|
2009
|
+
...props
|
|
2010
|
+
}: React.LabelHTMLAttributes<HTMLLabelElement>) {
|
|
2011
|
+
return (
|
|
2012
|
+
<label
|
|
2013
|
+
className={cn(
|
|
2014
|
+
'text-sm font-medium text-foreground',
|
|
2015
|
+
className
|
|
2016
|
+
)}
|
|
2017
|
+
{...props}
|
|
2018
|
+
/>
|
|
2019
|
+
)
|
|
2020
|
+
}
|
|
2021
|
+
`;var ie=`import * as React from 'react'
|
|
2022
|
+
import { ChevronLeft, ChevronRight, MoreHorizontal } from 'lucide-react'
|
|
2023
|
+
import { cn } from '@/utils/cn'
|
|
2024
|
+
|
|
2025
|
+
const styles = {
|
|
2026
|
+
nav: 'mx-auto flex w-full justify-center',
|
|
2027
|
+
content: 'flex flex-row items-center gap-1',
|
|
2028
|
+
link: cn(
|
|
2029
|
+
'inline-flex items-center justify-center',
|
|
2030
|
+
'h-9 min-w-9 px-3 rounded-[10px] text-sm',
|
|
2031
|
+
'text-muted-foreground hover:text-foreground',
|
|
2032
|
+
'hover:bg-accent transition-colors cursor-pointer'
|
|
2033
|
+
),
|
|
2034
|
+
active: cn(
|
|
2035
|
+
'bg-foreground text-background',
|
|
2036
|
+
'hover:bg-foreground hover:text-background'
|
|
2037
|
+
),
|
|
2038
|
+
nav_link: cn(
|
|
2039
|
+
'inline-flex items-center justify-center',
|
|
2040
|
+
'h-9 px-3 gap-1 rounded-[10px] text-sm',
|
|
2041
|
+
'text-muted-foreground hover:text-foreground',
|
|
2042
|
+
'hover:bg-accent transition-colors cursor-pointer'
|
|
2043
|
+
),
|
|
2044
|
+
ellipsis: cn(
|
|
2045
|
+
'flex h-9 w-9 items-center justify-center',
|
|
2046
|
+
'text-muted-foreground'
|
|
2047
|
+
),
|
|
2048
|
+
}
|
|
2049
|
+
|
|
2050
|
+
function PaginationRoot({
|
|
2051
|
+
className,
|
|
2052
|
+
...props
|
|
2053
|
+
}: React.ComponentProps<'nav'>) {
|
|
2054
|
+
return (
|
|
2055
|
+
<nav
|
|
2056
|
+
role="navigation"
|
|
2057
|
+
aria-label="pagination"
|
|
2058
|
+
className={cn(styles.nav, className)}
|
|
2059
|
+
{...props}
|
|
2060
|
+
/>
|
|
2061
|
+
)
|
|
2062
|
+
}
|
|
2063
|
+
|
|
2064
|
+
function Content({
|
|
2065
|
+
className,
|
|
2066
|
+
...props
|
|
2067
|
+
}: React.ComponentProps<'ul'>) {
|
|
2068
|
+
return (
|
|
2069
|
+
<ul
|
|
2070
|
+
className={cn(styles.content, className)}
|
|
2071
|
+
{...props}
|
|
2072
|
+
/>
|
|
2073
|
+
)
|
|
2074
|
+
}
|
|
2075
|
+
|
|
2076
|
+
function Item({
|
|
2077
|
+
className,
|
|
2078
|
+
...props
|
|
2079
|
+
}: React.ComponentProps<'li'>) {
|
|
2080
|
+
return <li className={className} {...props} />
|
|
2081
|
+
}
|
|
2082
|
+
|
|
2083
|
+
function Link({
|
|
2084
|
+
isActive,
|
|
2085
|
+
className,
|
|
2086
|
+
...props
|
|
2087
|
+
}: React.AnchorHTMLAttributes<HTMLAnchorElement> & {
|
|
2088
|
+
isActive?: boolean
|
|
2089
|
+
}) {
|
|
2090
|
+
return (
|
|
2091
|
+
<a
|
|
2092
|
+
aria-current={isActive ? 'page' : undefined}
|
|
2093
|
+
className={cn(styles.link, isActive && styles.active, className)}
|
|
2094
|
+
{...props}
|
|
2095
|
+
/>
|
|
2096
|
+
)
|
|
2097
|
+
}
|
|
2098
|
+
|
|
2099
|
+
function Previous({
|
|
2100
|
+
className,
|
|
2101
|
+
children,
|
|
2102
|
+
...props
|
|
2103
|
+
}: React.AnchorHTMLAttributes<HTMLAnchorElement>) {
|
|
2104
|
+
return (
|
|
2105
|
+
<a
|
|
2106
|
+
aria-label="Go to previous page"
|
|
2107
|
+
className={cn(styles.nav_link, className)}
|
|
2108
|
+
{...props}
|
|
2109
|
+
>
|
|
2110
|
+
<ChevronLeft className="h-4 w-4" />
|
|
2111
|
+
{children ?? <span>Previous</span>}
|
|
2112
|
+
</a>
|
|
2113
|
+
)
|
|
2114
|
+
}
|
|
2115
|
+
|
|
2116
|
+
function Next({
|
|
2117
|
+
className,
|
|
2118
|
+
children,
|
|
2119
|
+
...props
|
|
2120
|
+
}: React.AnchorHTMLAttributes<HTMLAnchorElement>) {
|
|
2121
|
+
return (
|
|
2122
|
+
<a
|
|
2123
|
+
aria-label="Go to next page"
|
|
2124
|
+
className={cn(styles.nav_link, className)}
|
|
2125
|
+
{...props}
|
|
2126
|
+
>
|
|
2127
|
+
{children ?? <span>Next</span>}
|
|
2128
|
+
<ChevronRight className="h-4 w-4" />
|
|
2129
|
+
</a>
|
|
2130
|
+
)
|
|
2131
|
+
}
|
|
2132
|
+
|
|
2133
|
+
function PaginationEllipsis({
|
|
2134
|
+
className,
|
|
2135
|
+
}: {
|
|
2136
|
+
className?: string
|
|
2137
|
+
}) {
|
|
2138
|
+
return (
|
|
2139
|
+
<span className={cn(styles.ellipsis, className)}>
|
|
2140
|
+
<MoreHorizontal className="h-4 w-4" />
|
|
2141
|
+
<span className="sr-only">More pages</span>
|
|
2142
|
+
</span>
|
|
2143
|
+
)
|
|
2144
|
+
}
|
|
2145
|
+
|
|
2146
|
+
export const Pagination = Object.assign(PaginationRoot, {
|
|
2147
|
+
Content,
|
|
2148
|
+
Item,
|
|
2149
|
+
Link,
|
|
2150
|
+
Previous,
|
|
2151
|
+
Next,
|
|
2152
|
+
Ellipsis: PaginationEllipsis,
|
|
2153
|
+
})
|
|
2154
|
+
`;var le=`'use client'
|
|
1007
2155
|
|
|
1008
2156
|
import * as React from 'react'
|
|
1009
2157
|
import { cn } from '@/utils/cn'
|
|
@@ -1106,9 +2254,9 @@ function usePopover() {
|
|
|
1106
2254
|
|
|
1107
2255
|
export const Popover = Object.assign(PopoverRoot, {
|
|
1108
2256
|
Trigger,
|
|
1109
|
-
Content
|
|
2257
|
+
Content
|
|
1110
2258
|
})
|
|
1111
|
-
`;var
|
|
2259
|
+
`;var de=`import * as React from 'react'
|
|
1112
2260
|
import { cn } from '@/utils/cn'
|
|
1113
2261
|
|
|
1114
2262
|
const styles = {
|
|
@@ -1146,7 +2294,156 @@ export function Progress({
|
|
|
1146
2294
|
</div>
|
|
1147
2295
|
)
|
|
1148
2296
|
}
|
|
1149
|
-
`;var
|
|
2297
|
+
`;var pe=`'use client'
|
|
2298
|
+
|
|
2299
|
+
import * as React from 'react'
|
|
2300
|
+
import { cn } from '@/utils/cn'
|
|
2301
|
+
|
|
2302
|
+
const styles = {
|
|
2303
|
+
group: 'flex flex-col gap-3',
|
|
2304
|
+
horizontal: 'flex-row gap-4',
|
|
2305
|
+
item: 'flex items-start gap-2 cursor-pointer',
|
|
2306
|
+
radio: cn(
|
|
2307
|
+
'aspect-square w-4 mt-[3px] border border-input shadow-xs',
|
|
2308
|
+
'transition-[color,box-shadow] flex-shrink-0',
|
|
2309
|
+
'flex items-center justify-center',
|
|
2310
|
+
'peer-focus-visible:ring-[3px]',
|
|
2311
|
+
'peer-focus-visible:ring-ring/50',
|
|
2312
|
+
'peer-focus-visible:border-ring'
|
|
2313
|
+
),
|
|
2314
|
+
checked: 'bg-foreground border-foreground',
|
|
2315
|
+
indicator: 'w-2 h-2 bg-background',
|
|
2316
|
+
label: 'text-sm font-medium text-foreground select-none',
|
|
2317
|
+
description: 'text-sm text-muted-foreground select-none',
|
|
2318
|
+
variants: {
|
|
2319
|
+
circle: 'rounded-full',
|
|
2320
|
+
square: 'rounded-[4px]',
|
|
2321
|
+
},
|
|
2322
|
+
indicators: {
|
|
2323
|
+
circle: 'rounded-full',
|
|
2324
|
+
square: 'rounded-[2px]',
|
|
2325
|
+
},
|
|
2326
|
+
}
|
|
2327
|
+
|
|
2328
|
+
interface RadioGroupCtx {
|
|
2329
|
+
value: string
|
|
2330
|
+
onSelect: (v: string) => void
|
|
2331
|
+
disabled?: boolean
|
|
2332
|
+
variant: 'circle' | 'square'
|
|
2333
|
+
}
|
|
2334
|
+
|
|
2335
|
+
function RadioGroupRoot({
|
|
2336
|
+
children,
|
|
2337
|
+
defaultValue,
|
|
2338
|
+
value: controlledValue,
|
|
2339
|
+
onValueChange,
|
|
2340
|
+
orientation = 'vertical',
|
|
2341
|
+
variant = 'circle',
|
|
2342
|
+
disabled,
|
|
2343
|
+
className,
|
|
2344
|
+
}: {
|
|
2345
|
+
children: React.ReactNode
|
|
2346
|
+
defaultValue?: string
|
|
2347
|
+
value?: string
|
|
2348
|
+
onValueChange?: (value: string) => void
|
|
2349
|
+
orientation?: 'vertical' | 'horizontal'
|
|
2350
|
+
variant?: 'circle' | 'square'
|
|
2351
|
+
disabled?: boolean
|
|
2352
|
+
className?: string
|
|
2353
|
+
}) {
|
|
2354
|
+
const [internal, setInternal] = React.useState(
|
|
2355
|
+
defaultValue ?? ''
|
|
2356
|
+
)
|
|
2357
|
+
const isControlled = controlledValue !== undefined
|
|
2358
|
+
const current = isControlled ? controlledValue : internal
|
|
2359
|
+
|
|
2360
|
+
const onSelect = (v: string) => {
|
|
2361
|
+
if (!isControlled) setInternal(v)
|
|
2362
|
+
onValueChange?.(v)
|
|
2363
|
+
}
|
|
2364
|
+
|
|
2365
|
+
return (
|
|
2366
|
+
<Ctx.Provider value={{ value: current, onSelect, disabled, variant }}>
|
|
2367
|
+
<div
|
|
2368
|
+
role="radiogroup"
|
|
2369
|
+
className={cn(
|
|
2370
|
+
styles.group,
|
|
2371
|
+
orientation === 'horizontal' && styles.horizontal,
|
|
2372
|
+
className
|
|
2373
|
+
)}
|
|
2374
|
+
>
|
|
2375
|
+
{children}
|
|
2376
|
+
</div>
|
|
2377
|
+
</Ctx.Provider>
|
|
2378
|
+
)
|
|
2379
|
+
}
|
|
2380
|
+
|
|
2381
|
+
const Item = React.forwardRef<
|
|
2382
|
+
HTMLInputElement,
|
|
2383
|
+
{
|
|
2384
|
+
value: string
|
|
2385
|
+
label?: string
|
|
2386
|
+
description?: string
|
|
2387
|
+
children?: React.ReactNode
|
|
2388
|
+
disabled?: boolean
|
|
2389
|
+
className?: string
|
|
2390
|
+
} & Omit<
|
|
2391
|
+
React.InputHTMLAttributes<HTMLInputElement>,
|
|
2392
|
+
'type' | 'value'
|
|
2393
|
+
>
|
|
2394
|
+
>(({ value, label, description, children, disabled, className, ...props }, ref) => {
|
|
2395
|
+
const ctx = useRadioGroup()
|
|
2396
|
+
const isDisabled = disabled ?? ctx.disabled
|
|
2397
|
+
const isChecked = ctx.value === value
|
|
2398
|
+
|
|
2399
|
+
return (
|
|
2400
|
+
<label
|
|
2401
|
+
className={cn(
|
|
2402
|
+
styles.item,
|
|
2403
|
+
isDisabled && 'opacity-50 cursor-not-allowed',
|
|
2404
|
+
className
|
|
2405
|
+
)}
|
|
2406
|
+
>
|
|
2407
|
+
<input
|
|
2408
|
+
ref={ref}
|
|
2409
|
+
type="radio"
|
|
2410
|
+
className="peer sr-only"
|
|
2411
|
+
checked={isChecked}
|
|
2412
|
+
disabled={isDisabled}
|
|
2413
|
+
onChange={() => {
|
|
2414
|
+
if (!isDisabled) ctx.onSelect(value)
|
|
2415
|
+
}}
|
|
2416
|
+
{...props}
|
|
2417
|
+
/>
|
|
2418
|
+
<span className={cn(styles.radio, styles.variants[ctx.variant], isChecked && styles.checked)}>
|
|
2419
|
+
{isChecked && <span className={cn(styles.indicator, styles.indicators[ctx.variant])} />}
|
|
2420
|
+
</span>
|
|
2421
|
+
{children ?? (label && (
|
|
2422
|
+
<div className="flex flex-col gap-0.5">
|
|
2423
|
+
<span className={styles.label}>{label}</span>
|
|
2424
|
+
{description && (
|
|
2425
|
+
<span className={styles.description}>
|
|
2426
|
+
{description}
|
|
2427
|
+
</span>
|
|
2428
|
+
)}
|
|
2429
|
+
</div>
|
|
2430
|
+
))}
|
|
2431
|
+
</label>
|
|
2432
|
+
)
|
|
2433
|
+
})
|
|
2434
|
+
|
|
2435
|
+
Item.displayName = 'RadioGroup.Item'
|
|
2436
|
+
|
|
2437
|
+
const Ctx = React.createContext<RadioGroupCtx | null>(null)
|
|
2438
|
+
|
|
2439
|
+
function useRadioGroup() {
|
|
2440
|
+
const ctx = React.useContext(Ctx)
|
|
2441
|
+
if (!ctx) throw new Error('RadioGroup compound used outside <RadioGroup>')
|
|
2442
|
+
return ctx
|
|
2443
|
+
}
|
|
2444
|
+
|
|
2445
|
+
export const RadioGroup = Object.assign(RadioGroupRoot, { Item })
|
|
2446
|
+
`;var ue=`'use client'
|
|
1150
2447
|
|
|
1151
2448
|
import * as React from 'react'
|
|
1152
2449
|
import { ChevronDown } from 'lucide-react'
|
|
@@ -1298,9 +2595,9 @@ function useSelect() {
|
|
|
1298
2595
|
export const Select = Object.assign(SelectRoot, {
|
|
1299
2596
|
Trigger,
|
|
1300
2597
|
Menu,
|
|
1301
|
-
Option
|
|
2598
|
+
Option
|
|
1302
2599
|
})
|
|
1303
|
-
`;var
|
|
2600
|
+
`;var me=`import * as React from 'react'
|
|
1304
2601
|
import { cn } from '@/utils/cn'
|
|
1305
2602
|
|
|
1306
2603
|
const styles = {
|
|
@@ -1324,7 +2621,7 @@ export function Separator({
|
|
|
1324
2621
|
/>
|
|
1325
2622
|
)
|
|
1326
2623
|
}
|
|
1327
|
-
`;var
|
|
2624
|
+
`;var fe=`'use client'
|
|
1328
2625
|
|
|
1329
2626
|
import * as React from 'react'
|
|
1330
2627
|
import { cn } from '@/utils/cn'
|
|
@@ -1365,7 +2662,7 @@ export function Switch({
|
|
|
1365
2662
|
</button>
|
|
1366
2663
|
)
|
|
1367
2664
|
}
|
|
1368
|
-
`;var
|
|
2665
|
+
`;var ge=`'use client'
|
|
1369
2666
|
|
|
1370
2667
|
import * as React from 'react'
|
|
1371
2668
|
import { cn } from '@/utils/cn'
|
|
@@ -1477,9 +2774,9 @@ function useTabs() {
|
|
|
1477
2774
|
export const Tabs = Object.assign(TabsRoot, {
|
|
1478
2775
|
List,
|
|
1479
2776
|
Tab,
|
|
1480
|
-
Panel
|
|
2777
|
+
Panel
|
|
1481
2778
|
})
|
|
1482
|
-
`;var
|
|
2779
|
+
`;var he=`import * as React from 'react'
|
|
1483
2780
|
import { cn } from '@/utils/cn'
|
|
1484
2781
|
|
|
1485
2782
|
const styles = {
|
|
@@ -1506,7 +2803,7 @@ export const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(({
|
|
|
1506
2803
|
))
|
|
1507
2804
|
|
|
1508
2805
|
Textarea.displayName = 'Textarea'
|
|
1509
|
-
`;var
|
|
2806
|
+
`;var be=`'use client'
|
|
1510
2807
|
|
|
1511
2808
|
import * as React from 'react'
|
|
1512
2809
|
import { Toaster as Sonner, toast } from 'sonner'
|
|
@@ -1549,7 +2846,181 @@ function Toaster() {
|
|
|
1549
2846
|
}
|
|
1550
2847
|
|
|
1551
2848
|
export { Toaster, toast }
|
|
1552
|
-
`;var
|
|
2849
|
+
`;var ve=`import * as React from 'react'
|
|
2850
|
+
import { cn } from '@/utils/cn'
|
|
2851
|
+
|
|
2852
|
+
const styles = {
|
|
2853
|
+
wrapper: 'w-full overflow-x-auto',
|
|
2854
|
+
base: 'w-full caption-bottom text-sm border-collapse',
|
|
2855
|
+
variants: {
|
|
2856
|
+
default: '',
|
|
2857
|
+
striped: '[&_tbody_tr:nth-child(even)]:bg-muted/30',
|
|
2858
|
+
bordered: '[&_th]:border [&_td]:border',
|
|
2859
|
+
},
|
|
2860
|
+
caption: 'mt-3 text-sm text-muted-foreground',
|
|
2861
|
+
header: '[&_tr]:border-b [&_tr]:border-border',
|
|
2862
|
+
body: '[&_tr:last-child]:border-0',
|
|
2863
|
+
footer: 'border-t border-border bg-muted/30 font-medium',
|
|
2864
|
+
row: 'border-b border-border transition-colors hover:bg-muted/40',
|
|
2865
|
+
head: cn(
|
|
2866
|
+
'px-4 py-2.5 text-left font-semibold',
|
|
2867
|
+
'text-muted-foreground',
|
|
2868
|
+
'[&[align=center]]:text-center',
|
|
2869
|
+
'[&[align=right]]:text-right'
|
|
2870
|
+
),
|
|
2871
|
+
cell: cn(
|
|
2872
|
+
'px-4 py-2.5 text-foreground',
|
|
2873
|
+
'[&[align=center]]:text-center',
|
|
2874
|
+
'[&[align=right]]:text-right'
|
|
2875
|
+
),
|
|
2876
|
+
}
|
|
2877
|
+
|
|
2878
|
+
function TableRoot({
|
|
2879
|
+
variant = 'default',
|
|
2880
|
+
className,
|
|
2881
|
+
children,
|
|
2882
|
+
...props
|
|
2883
|
+
}: {
|
|
2884
|
+
variant?: keyof typeof styles.variants
|
|
2885
|
+
className?: string
|
|
2886
|
+
children: React.ReactNode
|
|
2887
|
+
} & Omit<
|
|
2888
|
+
React.ComponentPropsWithoutRef<'table'>,
|
|
2889
|
+
'className' | 'children'
|
|
2890
|
+
>) {
|
|
2891
|
+
return (
|
|
2892
|
+
<div className={styles.wrapper}>
|
|
2893
|
+
<table
|
|
2894
|
+
className={cn(
|
|
2895
|
+
styles.base,
|
|
2896
|
+
styles.variants[variant],
|
|
2897
|
+
className
|
|
2898
|
+
)}
|
|
2899
|
+
{...props}
|
|
2900
|
+
>
|
|
2901
|
+
{children}
|
|
2902
|
+
</table>
|
|
2903
|
+
</div>
|
|
2904
|
+
)
|
|
2905
|
+
}
|
|
2906
|
+
|
|
2907
|
+
function Caption({
|
|
2908
|
+
className,
|
|
2909
|
+
children,
|
|
2910
|
+
...props
|
|
2911
|
+
}: React.ComponentPropsWithoutRef<'caption'>) {
|
|
2912
|
+
return (
|
|
2913
|
+
<caption
|
|
2914
|
+
className={cn(styles.caption, className)}
|
|
2915
|
+
{...props}
|
|
2916
|
+
>
|
|
2917
|
+
{children}
|
|
2918
|
+
</caption>
|
|
2919
|
+
)
|
|
2920
|
+
}
|
|
2921
|
+
|
|
2922
|
+
function Header({
|
|
2923
|
+
className,
|
|
2924
|
+
children,
|
|
2925
|
+
...props
|
|
2926
|
+
}: React.ComponentPropsWithoutRef<'thead'>) {
|
|
2927
|
+
return (
|
|
2928
|
+
<thead
|
|
2929
|
+
className={cn(styles.header, className)}
|
|
2930
|
+
{...props}
|
|
2931
|
+
>
|
|
2932
|
+
{children}
|
|
2933
|
+
</thead>
|
|
2934
|
+
)
|
|
2935
|
+
}
|
|
2936
|
+
|
|
2937
|
+
function Body({
|
|
2938
|
+
className,
|
|
2939
|
+
children,
|
|
2940
|
+
...props
|
|
2941
|
+
}: React.ComponentPropsWithoutRef<'tbody'>) {
|
|
2942
|
+
return (
|
|
2943
|
+
<tbody
|
|
2944
|
+
className={cn(styles.body, className)}
|
|
2945
|
+
{...props}
|
|
2946
|
+
>
|
|
2947
|
+
{children}
|
|
2948
|
+
</tbody>
|
|
2949
|
+
)
|
|
2950
|
+
}
|
|
2951
|
+
|
|
2952
|
+
function Footer({
|
|
2953
|
+
className,
|
|
2954
|
+
children,
|
|
2955
|
+
...props
|
|
2956
|
+
}: React.ComponentPropsWithoutRef<'tfoot'>) {
|
|
2957
|
+
return (
|
|
2958
|
+
<tfoot
|
|
2959
|
+
className={cn(styles.footer, className)}
|
|
2960
|
+
{...props}
|
|
2961
|
+
>
|
|
2962
|
+
{children}
|
|
2963
|
+
</tfoot>
|
|
2964
|
+
)
|
|
2965
|
+
}
|
|
2966
|
+
|
|
2967
|
+
function Row({
|
|
2968
|
+
className,
|
|
2969
|
+
children,
|
|
2970
|
+
...props
|
|
2971
|
+
}: React.ComponentPropsWithoutRef<'tr'>) {
|
|
2972
|
+
return (
|
|
2973
|
+
<tr
|
|
2974
|
+
className={cn(styles.row, className)}
|
|
2975
|
+
{...props}
|
|
2976
|
+
>
|
|
2977
|
+
{children}
|
|
2978
|
+
</tr>
|
|
2979
|
+
)
|
|
2980
|
+
}
|
|
2981
|
+
|
|
2982
|
+
function Head({
|
|
2983
|
+
scope = 'col',
|
|
2984
|
+
className,
|
|
2985
|
+
children,
|
|
2986
|
+
...props
|
|
2987
|
+
}: React.ComponentPropsWithoutRef<'th'>) {
|
|
2988
|
+
return (
|
|
2989
|
+
<th
|
|
2990
|
+
scope={scope}
|
|
2991
|
+
className={cn(styles.head, className)}
|
|
2992
|
+
{...props}
|
|
2993
|
+
>
|
|
2994
|
+
{children}
|
|
2995
|
+
</th>
|
|
2996
|
+
)
|
|
2997
|
+
}
|
|
2998
|
+
|
|
2999
|
+
function Cell({
|
|
3000
|
+
className,
|
|
3001
|
+
children,
|
|
3002
|
+
...props
|
|
3003
|
+
}: React.ComponentPropsWithoutRef<'td'>) {
|
|
3004
|
+
return (
|
|
3005
|
+
<td
|
|
3006
|
+
className={cn(styles.cell, className)}
|
|
3007
|
+
{...props}
|
|
3008
|
+
>
|
|
3009
|
+
{children}
|
|
3010
|
+
</td>
|
|
3011
|
+
)
|
|
3012
|
+
}
|
|
3013
|
+
|
|
3014
|
+
export const Table = Object.assign(TableRoot, {
|
|
3015
|
+
Caption,
|
|
3016
|
+
Header,
|
|
3017
|
+
Body,
|
|
3018
|
+
Footer,
|
|
3019
|
+
Row,
|
|
3020
|
+
Head,
|
|
3021
|
+
Cell,
|
|
3022
|
+
})
|
|
3023
|
+
`;var xe=`import * as React from 'react'
|
|
1553
3024
|
import { cn } from '@/utils/cn'
|
|
1554
3025
|
|
|
1555
3026
|
const styles = {
|
|
@@ -1594,4 +3065,15 @@ export function Tooltip({
|
|
|
1594
3065
|
</span>
|
|
1595
3066
|
)
|
|
1596
3067
|
}
|
|
1597
|
-
`;var
|
|
3068
|
+
`;var ye=`
|
|
3069
|
+
/* react-day-picker theme integration */
|
|
3070
|
+
.rdp-root {
|
|
3071
|
+
--rdp-accent-color: var(--primary);
|
|
3072
|
+
--rdp-accent-background-color: var(--accent);
|
|
3073
|
+
--rdp-day-height: 36px;
|
|
3074
|
+
--rdp-day-width: 36px;
|
|
3075
|
+
--rdp-selected-font: inherit;
|
|
3076
|
+
--rdp-selected-border: none;
|
|
3077
|
+
--rdp-day_button-border: none;
|
|
3078
|
+
}
|
|
3079
|
+
`,w=[{name:"accordion",description:"Collapsible content sections with dot notation and smooth animation",dependencies:[],npmDependencies:[]},{name:"alert",description:"Contextual feedback messages with variants and icons",dependencies:[],npmDependencies:[]},{name:"avatar",description:"User avatar with image support and fallback initials",dependencies:[],npmDependencies:[]},{name:"badge",description:"Small status indicator with color variants",dependencies:[],npmDependencies:[]},{name:"breadcrumb",description:"Breadcrumb navigation with auto-separators, ellipsis, and dot notation",dependencies:[],npmDependencies:[]},{name:"button",description:"Button with variants, sizes, loading state, and icon slots",dependencies:[],npmDependencies:[]},{name:"calendar",description:"Date picker powered by react-day-picker with single, range, and dropdown modes",dependencies:[],npmDependencies:["react-day-picker"]},{name:"date-picker",description:"Date picker input with Calendar dropdown for single date and range selection",dependencies:["calendar"],npmDependencies:[]},{name:"command",description:"Searchable command menu with filtering, keyboard navigation, and dialog mode",dependencies:["dialog"],npmDependencies:["cmdk"]},{name:"carousel",description:"Carousel with touch/swipe, navigation arrows, dot indicators, and loop mode",dependencies:["button"],npmDependencies:["embla-carousel-react"]},{name:"card",description:"Container with dot notation preview and info sub-components",dependencies:[],npmDependencies:[]},{name:"checkbox",description:"Checkbox input with label and CSS-only checkmark",dependencies:[],npmDependencies:[]},{name:"dialog",description:"Modal dialog with dot notation, overlay, and escape key",dependencies:["button"],npmDependencies:[]},{name:"dropdown",description:"Dropdown menu with dot notation, groups, separators, and click-outside",dependencies:["button"],npmDependencies:[]},{name:"input",description:"Text input with focus ring and disabled state",dependencies:[],npmDependencies:[]},{name:"label",description:"Accessible form label for inputs, checkboxes, and selects",dependencies:[],npmDependencies:[]},{name:"pagination",description:"Page navigation with dot notation, Previous/Next, ellipsis, and active state",dependencies:[],npmDependencies:[]},{name:"popover",description:"Floating content panel with dot notation and click-outside",dependencies:["button"],npmDependencies:[]},{name:"progress",description:"Progress bar with animated fill and ARIA attributes",dependencies:[],npmDependencies:[]},{name:"radio-group",description:"Radio group with dot notation, orientation support, and controlled/uncontrolled selection",dependencies:[],npmDependencies:[]},{name:"select",description:"Custom select with dot notation and composable options",dependencies:[],npmDependencies:[]},{name:"separator",description:"Visual divider with horizontal and vertical orientation",dependencies:[],npmDependencies:[]},{name:"switch",description:"Toggle switch with smooth transition",dependencies:[],npmDependencies:[]},{name:"tabs",description:"Tab navigation with dot notation and panel content",dependencies:[],npmDependencies:[]},{name:"table",description:"Data table with dot notation, striped/bordered variants, and responsive overflow",dependencies:[],npmDependencies:[]},{name:"textarea",description:"Multi-line text input with consistent styling",dependencies:[],npmDependencies:[]},{name:"theme",description:"Dark/light theme support with next-themes and ThemeProvider",dependencies:[],npmDependencies:["next-themes"]},{name:"toast",description:"Toast notifications powered by Sonner",dependencies:[],npmDependencies:["sonner"]},{name:"tooltip",description:"Pure CSS tooltip with 4 position options",dependencies:[],npmDependencies:[]}],S={accordion:Y,alert:W,avatar:U,badge:q,breadcrumb:X,button:J,calendar:Q,"date-picker":Z,command:ee,carousel:te,card:oe,checkbox:ne,dialog:re,dropdown:se,input:ae,label:ce,pagination:ie,popover:le,progress:de,"radio-group":pe,select:ue,separator:me,switch:fe,table:ve,tabs:ge,textarea:he,theme:K,toast:be,tooltip:xe};async function Ne(t){let n=process.cwd();e.intro("drivn add");let a=_(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:w.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 b=t.filter(o=>!w.find(r=>r.name===o));b.length&&(e.log.error(`Unknown components: ${b.join(", ")}`),e.log.info("Available: "+w.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,v=new Set,h=o=>{if(u.has(o))return;let r=w.find(c=>c.name===o);r&&(r.dependencies.forEach(c=>h(c)),r.npmDependencies?.forEach(c=>v.add(c)),u.add(o));};g.forEach(h),p&&v.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=M(c);C.includes('[data-theme="dark"]')?e.log.warn("Theme tokens already exist in globals \u2014 skipped"):(d(c,C+O),e.log.success(`Theme tokens appended to ${i.cyan(a.paths.globals)}`));}else e.log.warn(`Globals file not found at ${a.paths.globals}`);}else e.log.warn('No globals path in drivn.config.json. Add "globals" to paths');let r=a.paths.components.replace(/^src\//,"@/");e.log.message(""),e.log.info(i.bold("Complete the setup:")),e.log.message(""),e.log.message(i.bold(`${i.cyan("1.")} Import ThemeProvider in your root layout:`)),e.log.message(i.cyan(` import { ThemeProvider } from "${r}/theme-provider"`)),e.log.message(""),e.log.message(i.bold(`${i.cyan("2.")} Add suppressHydrationWarning to <html>:`)),e.log.message(i.cyan(" <html suppressHydrationWarning>")),e.log.message(""),e.log.message(i.bold(`${i.cyan("3.")} Wrap your app with ThemeProvider:`)),e.log.message(i.cyan(" <ThemeProvider>")),e.log.message(i.cyan(" {children}")),e.log.message(i.cyan(" </ThemeProvider>")),e.log.message("");}if(u.has("calendar")&&a.paths.globals){let o=join(n,a.paths.globals);if(m(o)){let r=M(o);r.includes(".rdp-root")?e.log.warn("Calendar tokens already exist in globals \u2014 skipped"):(d(o,r+ye),e.log.success(`Calendar tokens appended to ${i.cyan(a.paths.globals)}`));}}if(v.size){let o=P(n),r=[...v],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 Ce={version:"1.3.0"};var T=new Command;T.name("drivn").description("Drivn \u2014 Modern UI components").version(Ce.version);T.command("create").description("Initialize Drivn in your project").action(G);T.command("add [components...]").description("Add components to your project").action(Ne);T.parse();
|