@betterstart/cli 0.1.28 → 0.1.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/dist/{chunk-SAPJG4NO.js → chunk-6JCWMKSY.js} +7 -4
  2. package/dist/{chunk-SAPJG4NO.js.map → chunk-6JCWMKSY.js.map} +1 -1
  3. package/dist/cli.js +749 -866
  4. package/dist/cli.js.map +1 -1
  5. package/dist/drizzle-config-EDKOEZ6G.js +7 -0
  6. package/package.json +1 -1
  7. package/templates/ui/accordion.tsx +73 -42
  8. package/templates/ui/alert-dialog.tsx +155 -90
  9. package/templates/ui/alert.tsx +46 -26
  10. package/templates/ui/aspect-ratio.tsx +4 -2
  11. package/templates/ui/avatar.tsx +92 -43
  12. package/templates/ui/badge.tsx +27 -12
  13. package/templates/ui/breadcrumb.tsx +63 -60
  14. package/templates/ui/button-group.tsx +8 -8
  15. package/templates/ui/button.tsx +44 -26
  16. package/templates/ui/calendar.tsx +43 -34
  17. package/templates/ui/card.tsx +71 -34
  18. package/templates/ui/carousel.tsx +111 -115
  19. package/templates/ui/chart.tsx +197 -207
  20. package/templates/ui/checkbox.tsx +21 -20
  21. package/templates/ui/collapsible.tsx +14 -4
  22. package/templates/ui/combobox.tsx +272 -0
  23. package/templates/ui/command.tsx +139 -101
  24. package/templates/ui/context-menu.tsx +214 -156
  25. package/templates/ui/dialog.tsx +118 -77
  26. package/templates/ui/direction.tsx +20 -0
  27. package/templates/ui/drawer.tsx +89 -69
  28. package/templates/ui/dropdown-menu.tsx +228 -164
  29. package/templates/ui/empty.tsx +8 -5
  30. package/templates/ui/field.tsx +25 -32
  31. package/templates/ui/hover-card.tsx +29 -20
  32. package/templates/ui/input-group.tsx +20 -37
  33. package/templates/ui/input-otp.tsx +57 -42
  34. package/templates/ui/input.tsx +14 -17
  35. package/templates/ui/item.tsx +27 -17
  36. package/templates/ui/kbd.tsx +1 -3
  37. package/templates/ui/label.tsx +14 -14
  38. package/templates/ui/markdown-editor.tsx +1 -1
  39. package/templates/ui/menubar.tsx +220 -188
  40. package/templates/ui/native-select.tsx +42 -0
  41. package/templates/ui/navigation-menu.tsx +130 -90
  42. package/templates/ui/pagination.tsx +88 -73
  43. package/templates/ui/popover.tsx +67 -26
  44. package/templates/ui/progress.tsx +24 -18
  45. package/templates/ui/radio-group.tsx +26 -20
  46. package/templates/ui/resizable.tsx +29 -29
  47. package/templates/ui/scroll-area.tsx +47 -38
  48. package/templates/ui/select.tsx +158 -125
  49. package/templates/ui/separator.tsx +21 -19
  50. package/templates/ui/sheet.tsx +104 -95
  51. package/templates/ui/sidebar.tsx +77 -183
  52. package/templates/ui/skeleton.tsx +8 -2
  53. package/templates/ui/slider.tsx +46 -17
  54. package/templates/ui/sonner.tsx +19 -9
  55. package/templates/ui/spinner.tsx +2 -2
  56. package/templates/ui/switch.tsx +24 -20
  57. package/templates/ui/table.tsx +68 -73
  58. package/templates/ui/tabs.tsx +71 -46
  59. package/templates/ui/textarea.tsx +13 -16
  60. package/templates/ui/toggle-group.tsx +57 -28
  61. package/templates/ui/toggle.tsx +21 -20
  62. package/templates/ui/tooltip.tsx +44 -23
  63. package/dist/drizzle-config-KISB26BA.js +0 -7
  64. package/templates/ui/use-mobile.tsx +0 -19
  65. /package/dist/{drizzle-config-KISB26BA.js.map → drizzle-config-EDKOEZ6G.js.map} +0 -0
@@ -1,10 +1,10 @@
1
1
  'use client'
2
2
 
3
+ import { Button, buttonVariants } from '@cms/components/ui/button'
3
4
  import { cn } from '@cms/utils/cn'
4
- import { ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon } from 'lucide-react'
5
+ import { ChevronDown, ChevronLeft, ChevronRight } from 'lucide-react'
5
6
  import * as React from 'react'
6
- import { type DayButton, DayPicker, getDefaultClassNames } from 'react-day-picker'
7
- import { Button, buttonVariants } from './button'
7
+ import { type DayButton, DayPicker, getDefaultClassNames, type Locale } from 'react-day-picker'
8
8
 
9
9
  function Calendar({
10
10
  className,
@@ -12,6 +12,7 @@ function Calendar({
12
12
  showOutsideDays = true,
13
13
  captionLayout = 'label',
14
14
  buttonVariant = 'ghost',
15
+ locale,
15
16
  formatters,
16
17
  components,
17
18
  ...props
@@ -24,75 +25,82 @@ function Calendar({
24
25
  <DayPicker
25
26
  showOutsideDays={showOutsideDays}
26
27
  className={cn(
27
- 'bg-background group/calendar p-3 [--cell-size:2rem] [[data-slot=card-content]_&]:bg-transparent [[data-slot=popover-content]_&]:bg-transparent',
28
+ 'bg-background group/calendar p-2 [--cell-radius:var(--radius-md)] [--cell-size:--spacing(7)] in-data-[slot=card-content]:bg-transparent in-data-[slot=popover-content]:bg-transparent',
28
29
  String.raw`rtl:**:[.rdp-button\_next>svg]:rotate-180`,
29
30
  String.raw`rtl:**:[.rdp-button\_previous>svg]:rotate-180`,
30
31
  className
31
32
  )}
32
33
  captionLayout={captionLayout}
34
+ locale={locale}
33
35
  formatters={{
34
- formatMonthDropdown: (date) => date.toLocaleString('default', { month: 'short' }),
36
+ formatMonthDropdown: (date) => date.toLocaleString(locale?.code, { month: 'short' }),
35
37
  ...formatters
36
38
  }}
37
39
  classNames={{
38
40
  root: cn('w-fit', defaultClassNames.root),
39
- months: cn('relative flex flex-col gap-4 md:flex-row', defaultClassNames.months),
40
- month: cn('flex w-full flex-col gap-4', defaultClassNames.month),
41
+ months: cn('flex gap-4 flex-col md:flex-row relative', defaultClassNames.months),
42
+ month: cn('flex flex-col w-full gap-4', defaultClassNames.month),
41
43
  nav: cn(
42
- 'absolute inset-x-0 top-0 flex w-full items-center justify-between gap-1',
44
+ 'flex items-center gap-1 w-full absolute top-0 inset-x-0 justify-between',
43
45
  defaultClassNames.nav
44
46
  ),
45
47
  button_previous: cn(
46
48
  buttonVariants({ variant: buttonVariant }),
47
- 'h-[--cell-size] w-[--cell-size] select-none p-0 aria-disabled:opacity-50',
49
+ 'size-(--cell-size) aria-disabled:opacity-50 p-0 select-none',
48
50
  defaultClassNames.button_previous
49
51
  ),
50
52
  button_next: cn(
51
53
  buttonVariants({ variant: buttonVariant }),
52
- 'h-[--cell-size] w-[--cell-size] select-none p-0 aria-disabled:opacity-50',
54
+ 'size-(--cell-size) aria-disabled:opacity-50 p-0 select-none',
53
55
  defaultClassNames.button_next
54
56
  ),
55
57
  month_caption: cn(
56
- 'flex h-[--cell-size] w-full items-center justify-center px-[--cell-size]',
58
+ 'flex items-center justify-center h-(--cell-size) w-full px-(--cell-size)',
57
59
  defaultClassNames.month_caption
58
60
  ),
59
61
  dropdowns: cn(
60
- 'flex h-[--cell-size] w-full items-center justify-center gap-1.5 text-sm font-medium',
62
+ 'w-full flex items-center text-sm font-medium justify-center h-(--cell-size) gap-1.5',
61
63
  defaultClassNames.dropdowns
62
64
  ),
63
- dropdown_root: cn(
64
- 'has-focus:border-ring border-input-border shadow-xs has-focus:ring-ring/50 has-focus:ring-[3px] relative rounded-md border',
65
- defaultClassNames.dropdown_root
66
- ),
67
- dropdown: cn('bg-popover absolute inset-0 opacity-0', defaultClassNames.dropdown),
65
+ dropdown_root: cn('relative rounded-(--cell-radius)', defaultClassNames.dropdown_root),
66
+ dropdown: cn('absolute bg-popover inset-0 opacity-0', defaultClassNames.dropdown),
68
67
  caption_label: cn(
69
68
  'select-none font-medium',
70
69
  captionLayout === 'label'
71
70
  ? 'text-sm'
72
- : '[&>svg]:text-muted-foreground flex h-8 items-center gap-1 rounded-md pl-2 pr-1 text-sm [&>svg]:size-3.5',
71
+ : 'rounded-(--cell-radius) flex items-center gap-1 text-sm [&>svg]:text-muted-foreground [&>svg]:size-3.5',
73
72
  defaultClassNames.caption_label
74
73
  ),
75
74
  table: 'w-full border-collapse',
76
75
  weekdays: cn('flex', defaultClassNames.weekdays),
77
76
  weekday: cn(
78
- 'text-muted-foreground flex-1 select-none rounded-md text-[0.8rem] font-normal',
77
+ 'text-muted-foreground rounded-(--cell-radius) flex-1 font-normal text-[0.8rem] select-none',
79
78
  defaultClassNames.weekday
80
79
  ),
81
- week: cn('mt-2 flex w-full', defaultClassNames.week),
82
- week_number_header: cn('w-[--cell-size] select-none', defaultClassNames.week_number_header),
80
+ week: cn('flex w-full mt-2', defaultClassNames.week),
81
+ week_number_header: cn('select-none w-(--cell-size)', defaultClassNames.week_number_header),
83
82
  week_number: cn(
84
- 'text-muted-foreground select-none text-[0.8rem]',
83
+ 'text-[0.8rem] select-none text-muted-foreground',
85
84
  defaultClassNames.week_number
86
85
  ),
87
86
  day: cn(
88
- 'group/day relative aspect-square h-full w-full select-none p-0 text-center [&:first-child[data-selected=true]_button]:rounded-l-md [&:last-child[data-selected=true]_button]:rounded-r-md',
87
+ 'relative w-full rounded-(--cell-radius) h-full p-0 text-center [&:last-child[data-selected=true]_button]:rounded-r-(--cell-radius) group/day aspect-square select-none',
88
+ props.showWeekNumber
89
+ ? '[&:nth-child(2)[data-selected=true]_button]:rounded-l-(--cell-radius)'
90
+ : '[&:first-child[data-selected=true]_button]:rounded-l-(--cell-radius)',
89
91
  defaultClassNames.day
90
92
  ),
91
- range_start: cn('bg-accent rounded-l-md', defaultClassNames.range_start),
93
+ range_start: cn(
94
+ 'rounded-l-(--cell-radius) bg-muted relative after:bg-muted after:absolute after:inset-y-0 after:w-4 after:right-0 z-0 isolate',
95
+ defaultClassNames.range_start
96
+ ),
92
97
  range_middle: cn('rounded-none', defaultClassNames.range_middle),
93
- range_end: cn('bg-accent rounded-r-md', defaultClassNames.range_end),
98
+ range_end: cn(
99
+ 'rounded-r-(--cell-radius) bg-muted relative after:bg-muted after:absolute after:inset-y-0 after:w-4 after:left-0 z-0 isolate',
100
+ defaultClassNames.range_end
101
+ ),
94
102
  today: cn(
95
- 'bg-accent text-accent-foreground rounded-md data-[selected=true]:rounded-none',
103
+ 'bg-muted text-foreground rounded-(--cell-radius) data-[selected=true]:rounded-none',
96
104
  defaultClassNames.today
97
105
  ),
98
106
  outside: cn(
@@ -109,20 +117,20 @@ function Calendar({
109
117
  },
110
118
  Chevron: ({ className, orientation, ...props }) => {
111
119
  if (orientation === 'left') {
112
- return <ChevronLeftIcon className={cn('size-4', className)} {...props} />
120
+ return <ChevronLeft className={cn('size-4', className)} {...props} />
113
121
  }
114
122
 
115
123
  if (orientation === 'right') {
116
- return <ChevronRightIcon className={cn('size-4', className)} {...props} />
124
+ return <ChevronRight className={cn('size-4', className)} {...props} />
117
125
  }
118
126
 
119
- return <ChevronDownIcon className={cn('size-4', className)} {...props} />
127
+ return <ChevronDown className={cn('size-4', className)} {...props} />
120
128
  },
121
- DayButton: CalendarDayButton,
129
+ DayButton: ({ ...props }) => <CalendarDayButton locale={locale} {...props} />,
122
130
  WeekNumber: ({ children, ...props }) => {
123
131
  return (
124
132
  <td {...props}>
125
- <div className="flex size-[--cell-size] items-center justify-center text-center">
133
+ <div className="flex size-(--cell-size) items-center justify-center text-center">
126
134
  {children}
127
135
  </div>
128
136
  </td>
@@ -139,8 +147,9 @@ function CalendarDayButton({
139
147
  className,
140
148
  day,
141
149
  modifiers,
150
+ locale,
142
151
  ...props
143
- }: React.ComponentProps<typeof DayButton>) {
152
+ }: React.ComponentProps<typeof DayButton> & { locale?: Partial<Locale> }) {
144
153
  const defaultClassNames = getDefaultClassNames()
145
154
 
146
155
  const ref = React.useRef<HTMLButtonElement>(null)
@@ -153,7 +162,7 @@ function CalendarDayButton({
153
162
  ref={ref}
154
163
  variant="ghost"
155
164
  size="icon"
156
- data-day={day.date.toLocaleDateString()}
165
+ data-day={day.date.toLocaleDateString(locale?.code)}
157
166
  data-selected-single={
158
167
  modifiers.selected &&
159
168
  !modifiers.range_start &&
@@ -164,7 +173,7 @@ function CalendarDayButton({
164
173
  data-range-end={modifiers.range_end}
165
174
  data-range-middle={modifiers.range_middle}
166
175
  className={cn(
167
- 'data-[selected-single=true]:bg-primary data-[selected-single=true]:text-primary-foreground data-[range-middle=true]:bg-accent data-[range-middle=true]:text-accent-foreground data-[range-start=true]:bg-primary data-[range-start=true]:text-primary-foreground data-[range-end=true]:bg-primary data-[range-end=true]:text-primary-foreground group-data-[focused=true]/day:border-ring group-data-[focused=true]/day:ring-ring/50 flex aspect-square h-auto w-full min-w-[--cell-size] flex-col gap-1 font-normal leading-none data-[range-end=true]:rounded-md data-[range-middle=true]:rounded-none data-[range-start=true]:rounded-md group-data-[focused=true]/day:relative group-data-[focused=true]/day:z-10 group-data-[focused=true]/day:ring-[3px] [&>span]:text-xs [&>span]:opacity-70',
176
+ 'data-[selected-single=true]:bg-primary data-[selected-single=true]:text-primary-foreground data-[range-middle=true]:bg-muted data-[range-middle=true]:text-foreground data-[range-start=true]:bg-primary data-[range-start=true]:text-primary-foreground data-[range-end=true]:bg-primary data-[range-end=true]:text-primary-foreground group-data-[focused=true]/day:border-ring group-data-[focused=true]/day:ring-ring/50 dark:hover:text-foreground relative isolate z-10 flex aspect-square size-auto w-full min-w-(--cell-size) flex-col gap-1 border-0 leading-none font-normal group-data-[focused=true]/day:relative group-data-[focused=true]/day:z-10 group-data-[focused=true]/day:ring-[3px] data-[range-end=true]:rounded-(--cell-radius) data-[range-end=true]:rounded-r-(--cell-radius) data-[range-middle=true]:rounded-none data-[range-start=true]:rounded-(--cell-radius) data-[range-start=true]:rounded-l-(--cell-radius) [&>span]:text-xs [&>span]:opacity-70',
168
177
  defaultClassNames.day,
169
178
  className
170
179
  )}
@@ -1,54 +1,91 @@
1
1
  import { cn } from '@cms/utils/cn'
2
- import * as React from 'react'
2
+ import type * as React from 'react'
3
3
 
4
- const Card = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
5
- ({ className, ...props }, ref) => (
4
+ function Card({
5
+ className,
6
+ size = 'default',
7
+ ...props
8
+ }: React.ComponentProps<'div'> & { size?: 'default' | 'sm' }) {
9
+ return (
6
10
  <div
7
- ref={ref}
8
- className={cn('rounded-xl border bg-card text-card-foreground shadow', className)}
11
+ data-slot="card"
12
+ data-size={size}
13
+ className={cn(
14
+ 'ring-foreground/10 bg-card text-card-foreground group/card flex flex-col gap-4 overflow-hidden rounded-xl py-4 text-sm ring-1 has-data-[slot=card-footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:gap-3 data-[size=sm]:py-3 data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl',
15
+ className
16
+ )}
9
17
  {...props}
10
18
  />
11
19
  )
12
- )
13
- Card.displayName = 'Card'
20
+ }
14
21
 
15
- const CardHeader = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
16
- ({ className, ...props }, ref) => (
17
- <div ref={ref} className={cn('flex flex-col space-y-1.5 p-6', className)} {...props} />
22
+ function CardHeader({ className, ...props }: React.ComponentProps<'div'>) {
23
+ return (
24
+ <div
25
+ data-slot="card-header"
26
+ className={cn(
27
+ 'group/card-header @container/card-header grid auto-rows-min items-start gap-1 rounded-t-xl px-4 group-data-[size=sm]/card:px-3 has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto] [.border-b]:pb-4 group-data-[size=sm]/card:[.border-b]:pb-3',
28
+ className
29
+ )}
30
+ {...props}
31
+ />
18
32
  )
19
- )
20
- CardHeader.displayName = 'CardHeader'
33
+ }
21
34
 
22
- const CardTitle = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
23
- ({ className, ...props }, ref) => (
35
+ function CardTitle({ className, ...props }: React.ComponentProps<'div'>) {
36
+ return (
24
37
  <div
25
- ref={ref}
26
- className={cn('font-semibold leading-none tracking-tight', className)}
38
+ data-slot="card-title"
39
+ className={cn(
40
+ 'text-base leading-snug font-medium group-data-[size=sm]/card:text-sm',
41
+ className
42
+ )}
27
43
  {...props}
28
44
  />
29
45
  )
30
- )
31
- CardTitle.displayName = 'CardTitle'
46
+ }
32
47
 
33
- const CardDescription = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
34
- ({ className, ...props }, ref) => (
35
- <div ref={ref} className={cn('text-sm text-muted-foreground', className)} {...props} />
48
+ function CardDescription({ className, ...props }: React.ComponentProps<'div'>) {
49
+ return (
50
+ <div
51
+ data-slot="card-description"
52
+ className={cn('text-muted-foreground text-sm', className)}
53
+ {...props}
54
+ />
36
55
  )
37
- )
38
- CardDescription.displayName = 'CardDescription'
56
+ }
39
57
 
40
- const CardContent = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
41
- ({ className, ...props }, ref) => (
42
- <div ref={ref} className={cn('p-6 pt-0', className)} {...props} />
58
+ function CardAction({ className, ...props }: React.ComponentProps<'div'>) {
59
+ return (
60
+ <div
61
+ data-slot="card-action"
62
+ className={cn('col-start-2 row-span-2 row-start-1 self-start justify-self-end', className)}
63
+ {...props}
64
+ />
43
65
  )
44
- )
45
- CardContent.displayName = 'CardContent'
66
+ }
46
67
 
47
- const CardFooter = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
48
- ({ className, ...props }, ref) => (
49
- <div ref={ref} className={cn('flex items-center p-6 pt-0', className)} {...props} />
68
+ function CardContent({ className, ...props }: React.ComponentProps<'div'>) {
69
+ return (
70
+ <div
71
+ data-slot="card-content"
72
+ className={cn('px-4 group-data-[size=sm]/card:px-3', className)}
73
+ {...props}
74
+ />
75
+ )
76
+ }
77
+
78
+ function CardFooter({ className, ...props }: React.ComponentProps<'div'>) {
79
+ return (
80
+ <div
81
+ data-slot="card-footer"
82
+ className={cn(
83
+ 'bg-muted/50 flex items-center rounded-b-xl border-t p-4 group-data-[size=sm]/card:p-3',
84
+ className
85
+ )}
86
+ {...props}
87
+ />
50
88
  )
51
- )
52
- CardFooter.displayName = 'CardFooter'
89
+ }
53
90
 
54
- export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }
91
+ export { Card, CardHeader, CardFooter, CardTitle, CardAction, CardDescription, CardContent }
@@ -1,10 +1,10 @@
1
1
  'use client'
2
2
 
3
+ import { Button } from '@cms/components/ui/button'
3
4
  import { cn } from '@cms/utils/cn'
4
5
  import useEmblaCarousel, { type UseEmblaCarouselType } from 'embla-carousel-react'
5
- import { ArrowLeft, ArrowRight } from 'lucide-react'
6
+ import { ChevronLeft, ChevronRight } from 'lucide-react'
6
7
  import * as React from 'react'
7
- import { Button } from './button'
8
8
 
9
9
  type CarouselApi = UseEmblaCarouselType[1]
10
10
  type UseCarouselParameters = Parameters<typeof useEmblaCarousel>
@@ -39,10 +39,15 @@ function useCarousel() {
39
39
  return context
40
40
  }
41
41
 
42
- const Carousel = React.forwardRef<
43
- HTMLDivElement,
44
- React.HTMLAttributes<HTMLDivElement> & CarouselProps
45
- >(({ orientation = 'horizontal', opts, setApi, plugins, className, children, ...props }, ref) => {
42
+ function Carousel({
43
+ orientation = 'horizontal',
44
+ opts,
45
+ setApi,
46
+ plugins,
47
+ className,
48
+ children,
49
+ ...props
50
+ }: React.ComponentProps<'div'> & CarouselProps) {
46
51
  const [carouselRef, api] = useEmblaCarousel(
47
52
  {
48
53
  ...opts,
@@ -54,10 +59,7 @@ const Carousel = React.forwardRef<
54
59
  const [canScrollNext, setCanScrollNext] = React.useState(false)
55
60
 
56
61
  const onSelect = React.useCallback((api: CarouselApi) => {
57
- if (!api) {
58
- return
59
- }
60
-
62
+ if (!api) return
61
63
  setCanScrollPrev(api.canScrollPrev())
62
64
  setCanScrollNext(api.canScrollNext())
63
65
  }, [])
@@ -84,18 +86,12 @@ const Carousel = React.forwardRef<
84
86
  )
85
87
 
86
88
  React.useEffect(() => {
87
- if (!api || !setApi) {
88
- return
89
- }
90
-
89
+ if (!api || !setApi) return
91
90
  setApi(api)
92
91
  }, [api, setApi])
93
92
 
94
93
  React.useEffect(() => {
95
- if (!api) {
96
- return
97
- }
98
-
94
+ if (!api) return
99
95
  onSelect(api)
100
96
  api.on('reInit', onSelect)
101
97
  api.on('select', onSelect)
@@ -119,116 +115,116 @@ const Carousel = React.forwardRef<
119
115
  }}
120
116
  >
121
117
  <div
122
- ref={ref}
123
118
  onKeyDownCapture={handleKeyDown}
124
119
  className={cn('relative', className)}
125
120
  role="region"
126
121
  aria-roledescription="carousel"
122
+ data-slot="carousel"
127
123
  {...props}
128
124
  >
129
125
  {children}
130
126
  </div>
131
127
  </CarouselContext.Provider>
132
128
  )
133
- })
134
- Carousel.displayName = 'Carousel'
135
-
136
- const CarouselContent = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
137
- ({ className, ...props }, ref) => {
138
- const { carouselRef, orientation } = useCarousel()
139
-
140
- return (
141
- <div ref={carouselRef} className="overflow-hidden">
142
- <div
143
- ref={ref}
144
- className={cn(
145
- 'flex',
146
- orientation === 'horizontal' ? '-ml-4' : '-mt-4 flex-col',
147
- className
148
- )}
149
- {...props}
150
- />
151
- </div>
152
- )
153
- }
154
- )
155
- CarouselContent.displayName = 'CarouselContent'
129
+ }
156
130
 
157
- const CarouselItem = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
158
- ({ className, ...props }, ref) => {
159
- const { orientation } = useCarousel()
131
+ function CarouselContent({ className, ...props }: React.ComponentProps<'div'>) {
132
+ const { carouselRef, orientation } = useCarousel()
160
133
 
161
- return (
134
+ return (
135
+ <div ref={carouselRef} className="overflow-hidden" data-slot="carousel-content">
162
136
  <div
163
- ref={ref}
164
- role="group"
165
- aria-roledescription="slide"
166
- className={cn(
167
- 'min-w-0 shrink-0 grow-0 basis-full',
168
- orientation === 'horizontal' ? 'pl-4' : 'pt-4',
169
- className
170
- )}
137
+ className={cn('flex', orientation === 'horizontal' ? '-ml-4' : '-mt-4 flex-col', className)}
171
138
  {...props}
172
139
  />
173
- )
174
- }
175
- )
176
- CarouselItem.displayName = 'CarouselItem'
177
-
178
- const CarouselPrevious = React.forwardRef<HTMLButtonElement, React.ComponentProps<typeof Button>>(
179
- ({ className, variant = 'outline', size = 'icon', ...props }, ref) => {
180
- const { orientation, scrollPrev, canScrollPrev } = useCarousel()
181
-
182
- return (
183
- <Button
184
- ref={ref}
185
- variant={variant}
186
- size={size}
187
- className={cn(
188
- 'absolute h-8 w-8 rounded-full',
189
- orientation === 'horizontal'
190
- ? '-left-12 top-1/2 -translate-y-1/2'
191
- : '-top-12 left-1/2 -translate-x-1/2 rotate-90',
192
- className
193
- )}
194
- disabled={!canScrollPrev}
195
- onClick={scrollPrev}
196
- {...props}
197
- >
198
- <ArrowLeft className="size-4" />
199
- <span className="sr-only">Previous slide</span>
200
- </Button>
201
- )
202
- }
203
- )
204
- CarouselPrevious.displayName = 'CarouselPrevious'
205
-
206
- const CarouselNext = React.forwardRef<HTMLButtonElement, React.ComponentProps<typeof Button>>(
207
- ({ className, variant = 'outline', size = 'icon', ...props }, ref) => {
208
- const { orientation, scrollNext, canScrollNext } = useCarousel()
209
-
210
- return (
211
- <Button
212
- ref={ref}
213
- variant={variant}
214
- size={size}
215
- className={cn(
216
- 'absolute h-8 w-8 rounded-full',
217
- orientation === 'horizontal'
218
- ? '-right-12 top-1/2 -translate-y-1/2'
219
- : '-bottom-12 left-1/2 -translate-x-1/2 rotate-90',
220
- className
221
- )}
222
- disabled={!canScrollNext}
223
- onClick={scrollNext}
224
- {...props}
225
- >
226
- <ArrowRight className="size-4" />
227
- <span className="sr-only">Next slide</span>
228
- </Button>
229
- )
230
- }
231
- )
232
- CarouselNext.displayName = 'CarouselNext'
140
+ </div>
141
+ )
142
+ }
233
143
 
234
- export { type CarouselApi, Carousel, CarouselContent, CarouselItem, CarouselPrevious, CarouselNext }
144
+ function CarouselItem({ className, ...props }: React.ComponentProps<'div'>) {
145
+ const { orientation } = useCarousel()
146
+
147
+ return (
148
+ <div
149
+ role="group"
150
+ aria-roledescription="slide"
151
+ data-slot="carousel-item"
152
+ className={cn(
153
+ 'min-w-0 shrink-0 grow-0 basis-full',
154
+ orientation === 'horizontal' ? 'pl-4' : 'pt-4',
155
+ className
156
+ )}
157
+ {...props}
158
+ />
159
+ )
160
+ }
161
+
162
+ function CarouselPrevious({
163
+ className,
164
+ variant = 'outline',
165
+ size = 'icon-sm',
166
+ ...props
167
+ }: React.ComponentProps<typeof Button>) {
168
+ const { orientation, scrollPrev, canScrollPrev } = useCarousel()
169
+
170
+ return (
171
+ <Button
172
+ data-slot="carousel-previous"
173
+ variant={variant}
174
+ size={size}
175
+ className={cn(
176
+ 'absolute touch-manipulation rounded-full',
177
+ orientation === 'horizontal'
178
+ ? 'top-1/2 -left-12 -translate-y-1/2'
179
+ : '-top-12 left-1/2 -translate-x-1/2 rotate-90',
180
+ className
181
+ )}
182
+ disabled={!canScrollPrev}
183
+ onClick={scrollPrev}
184
+ {...props}
185
+ >
186
+ <ChevronLeft />
187
+ <span className="sr-only">Previous slide</span>
188
+ </Button>
189
+ )
190
+ }
191
+
192
+ function CarouselNext({
193
+ className,
194
+ variant = 'outline',
195
+ size = 'icon-sm',
196
+ ...props
197
+ }: React.ComponentProps<typeof Button>) {
198
+ const { orientation, scrollNext, canScrollNext } = useCarousel()
199
+
200
+ return (
201
+ <Button
202
+ data-slot="carousel-next"
203
+ variant={variant}
204
+ size={size}
205
+ className={cn(
206
+ 'absolute touch-manipulation rounded-full',
207
+ orientation === 'horizontal'
208
+ ? 'top-1/2 -right-12 -translate-y-1/2'
209
+ : '-bottom-12 left-1/2 -translate-x-1/2 rotate-90',
210
+ className
211
+ )}
212
+ disabled={!canScrollNext}
213
+ onClick={scrollNext}
214
+ {...props}
215
+ >
216
+ <ChevronRight />
217
+ <span className="sr-only">Next slide</span>
218
+ </Button>
219
+ )
220
+ }
221
+
222
+ export {
223
+ type CarouselApi,
224
+ Carousel,
225
+ CarouselContent,
226
+ CarouselItem,
227
+ CarouselPrevious,
228
+ CarouselNext,
229
+ useCarousel
230
+ }