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.
- package/dist/index.js +1168 -349
- 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")),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
|
-
`,
|
|
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
|
|
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
|
-
`,
|
|
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
|
|
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
|
-
|
|
187
|
-
toggle: (
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
const Ctx = React.createContext<AccordionCtx | null>(null)
|
|
191
|
-
const ItemCtx = React.createContext<string | null>(null)
|
|
192
|
-
|
|
193
|
-
function useAccordion() {
|
|
194
|
-
const ctx = React.useContext(Ctx)
|
|
195
|
-
if (!ctx) throw new Error('Accordion compound used outside <Accordion>')
|
|
196
|
-
return ctx
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
function useItemValue() {
|
|
200
|
-
const value = React.useContext(ItemCtx)
|
|
201
|
-
if (!value) throw new Error(
|
|
202
|
-
'Accordion sub-component used outside <Accordion.Item>'
|
|
203
|
-
)
|
|
204
|
-
return value
|
|
186
|
+
open: Set<string>
|
|
187
|
+
toggle: (v: string) => void
|
|
205
188
|
}
|
|
206
189
|
|
|
207
190
|
function AccordionRoot({
|
|
208
191
|
children,
|
|
209
192
|
defaultValue,
|
|
193
|
+
multiple,
|
|
210
194
|
className,
|
|
211
195
|
}: {
|
|
212
196
|
children: React.ReactNode
|
|
213
|
-
defaultValue?: string
|
|
197
|
+
defaultValue?: string | string[]
|
|
198
|
+
multiple?: boolean
|
|
214
199
|
className?: string
|
|
215
200
|
}) {
|
|
216
|
-
const [
|
|
217
|
-
|
|
218
|
-
)
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
201
|
+
const [open, setOpen] = React.useState(() => new Set([defaultValue ?? []].flat()))
|
|
202
|
+
|
|
203
|
+
const toggle = (v: string) =>
|
|
204
|
+
setOpen((prev) => {
|
|
205
|
+
const next = new Set(multiple ? prev : [])
|
|
206
|
+
prev.has(v) ? next.delete(v) : next.add(v)
|
|
207
|
+
return next
|
|
208
|
+
})
|
|
224
209
|
|
|
225
210
|
return (
|
|
226
|
-
<Ctx.Provider value={{
|
|
211
|
+
<Ctx.Provider value={{ open, toggle }}>
|
|
227
212
|
<div className={cn(styles.base, className)}>
|
|
228
213
|
{children}
|
|
229
214
|
</div>
|
|
@@ -250,17 +235,20 @@ function Item({
|
|
|
250
235
|
function Trigger({
|
|
251
236
|
children,
|
|
252
237
|
className,
|
|
238
|
+
...props
|
|
253
239
|
}: {
|
|
254
240
|
children: React.ReactNode
|
|
255
241
|
className?: string
|
|
256
|
-
}) {
|
|
257
|
-
const {
|
|
258
|
-
const value =
|
|
259
|
-
const isOpen =
|
|
242
|
+
} & React.ButtonHTMLAttributes<HTMLButtonElement>) {
|
|
243
|
+
const { open, toggle } = useCtx()
|
|
244
|
+
const value = React.useContext(ItemCtx)
|
|
245
|
+
const isOpen = open.has(value)
|
|
260
246
|
return (
|
|
261
247
|
<button
|
|
248
|
+
aria-expanded={isOpen}
|
|
262
249
|
className={cn(styles.trigger, className)}
|
|
263
250
|
onClick={() => toggle(value)}
|
|
251
|
+
{...props}
|
|
264
252
|
>
|
|
265
253
|
{children}
|
|
266
254
|
<ChevronDown className={cn(styles.icon, isOpen && 'rotate-180')} />
|
|
@@ -275,11 +263,12 @@ function Content({
|
|
|
275
263
|
children: React.ReactNode
|
|
276
264
|
className?: string
|
|
277
265
|
}) {
|
|
278
|
-
const {
|
|
279
|
-
const value =
|
|
280
|
-
const isOpen =
|
|
266
|
+
const { open } = useCtx()
|
|
267
|
+
const value = React.useContext(ItemCtx)
|
|
268
|
+
const isOpen = open.has(value)
|
|
281
269
|
return (
|
|
282
270
|
<div
|
|
271
|
+
role="region"
|
|
283
272
|
className={styles.panel}
|
|
284
273
|
style={{ gridTemplateRows: isOpen ? '1fr' : '0fr' }}
|
|
285
274
|
>
|
|
@@ -290,12 +279,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
|
|
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
|
|
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
|
|
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
|
-
<
|
|
418
|
-
{
|
|
419
|
-
|
|
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
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
)
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
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
|
-
|
|
454
|
-
|
|
455
|
-
|
|
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
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
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
|
|
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
|
-
|
|
515
|
-
|
|
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
|
|
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
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
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
|
|
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
|
-
|
|
676
|
-
'fixed inset-0
|
|
677
|
-
'
|
|
678
|
-
'
|
|
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
|
|
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 =
|
|
720
|
-
(v
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
},
|
|
724
|
-
[controlled, onOpenChange]
|
|
725
|
-
)
|
|
1553
|
+
const setOpen = (v: boolean) => {
|
|
1554
|
+
onOpenChange?.(v)
|
|
1555
|
+
if (controlled === undefined) setUncontrolled(v)
|
|
1556
|
+
}
|
|
726
1557
|
|
|
727
|
-
return
|
|
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
|
-
|
|
762
|
-
|
|
763
|
-
|
|
1598
|
+
const el = ref.current
|
|
1599
|
+
if (!el) return
|
|
1600
|
+
const onCancel = (e: Event) => {
|
|
1601
|
+
e.preventDefault()
|
|
1602
|
+
setOpen(false)
|
|
764
1603
|
}
|
|
765
|
-
|
|
766
|
-
|
|
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
|
-
|
|
769
|
-
|
|
1619
|
+
el.removeEventListener('cancel', onCancel)
|
|
1620
|
+
clearTimeout(id)
|
|
770
1621
|
}
|
|
771
1622
|
}, [open, setOpen])
|
|
772
1623
|
|
|
773
1624
|
return (
|
|
774
|
-
<
|
|
775
|
-
|
|
776
|
-
|
|
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
|
-
|
|
787
|
-
styles.
|
|
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
|
-
</
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
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
|
|
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
|
|
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
|
|
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();
|