@betterstart/cli 0.1.28 → 0.1.29
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/{chunk-SAPJG4NO.js → chunk-6JCWMKSY.js} +7 -4
- package/dist/{chunk-SAPJG4NO.js.map → chunk-6JCWMKSY.js.map} +1 -1
- package/dist/cli.js +742 -869
- package/dist/cli.js.map +1 -1
- package/dist/drizzle-config-EDKOEZ6G.js +7 -0
- package/package.json +1 -1
- package/templates/ui/accordion.tsx +73 -42
- package/templates/ui/alert-dialog.tsx +155 -90
- package/templates/ui/alert.tsx +46 -26
- package/templates/ui/aspect-ratio.tsx +4 -2
- package/templates/ui/avatar.tsx +92 -43
- package/templates/ui/badge.tsx +27 -12
- package/templates/ui/breadcrumb.tsx +63 -60
- package/templates/ui/button-group.tsx +8 -8
- package/templates/ui/button.tsx +44 -26
- package/templates/ui/calendar.tsx +43 -34
- package/templates/ui/card.tsx +71 -34
- package/templates/ui/carousel.tsx +111 -115
- package/templates/ui/chart.tsx +197 -207
- package/templates/ui/checkbox.tsx +21 -20
- package/templates/ui/collapsible.tsx +14 -4
- package/templates/ui/combobox.tsx +272 -0
- package/templates/ui/command.tsx +139 -101
- package/templates/ui/context-menu.tsx +214 -156
- package/templates/ui/dialog.tsx +118 -77
- package/templates/ui/direction.tsx +20 -0
- package/templates/ui/drawer.tsx +89 -69
- package/templates/ui/dropdown-menu.tsx +228 -164
- package/templates/ui/empty.tsx +8 -5
- package/templates/ui/field.tsx +25 -32
- package/templates/ui/hover-card.tsx +29 -20
- package/templates/ui/input-group.tsx +20 -37
- package/templates/ui/input-otp.tsx +57 -42
- package/templates/ui/input.tsx +14 -17
- package/templates/ui/item.tsx +27 -17
- package/templates/ui/kbd.tsx +1 -3
- package/templates/ui/label.tsx +14 -14
- package/templates/ui/markdown-editor.tsx +1 -1
- package/templates/ui/menubar.tsx +220 -188
- package/templates/ui/native-select.tsx +42 -0
- package/templates/ui/navigation-menu.tsx +130 -90
- package/templates/ui/pagination.tsx +88 -73
- package/templates/ui/popover.tsx +67 -26
- package/templates/ui/progress.tsx +24 -18
- package/templates/ui/radio-group.tsx +26 -20
- package/templates/ui/resizable.tsx +29 -29
- package/templates/ui/scroll-area.tsx +47 -38
- package/templates/ui/select.tsx +158 -125
- package/templates/ui/separator.tsx +21 -19
- package/templates/ui/sheet.tsx +104 -95
- package/templates/ui/sidebar.tsx +77 -183
- package/templates/ui/skeleton.tsx +8 -2
- package/templates/ui/slider.tsx +46 -17
- package/templates/ui/sonner.tsx +19 -9
- package/templates/ui/spinner.tsx +2 -2
- package/templates/ui/switch.tsx +24 -20
- package/templates/ui/table.tsx +68 -73
- package/templates/ui/tabs.tsx +71 -46
- package/templates/ui/textarea.tsx +13 -16
- package/templates/ui/toggle-group.tsx +57 -28
- package/templates/ui/toggle.tsx +21 -20
- package/templates/ui/tooltip.tsx +44 -23
- package/dist/drizzle-config-KISB26BA.js +0 -7
- package/templates/ui/use-mobile.tsx +0 -19
- /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 {
|
|
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-
|
|
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(
|
|
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('
|
|
40
|
-
month: cn('flex w-full
|
|
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
|
-
'
|
|
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
|
-
'
|
|
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
|
-
'
|
|
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-
|
|
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
|
-
'
|
|
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
|
-
|
|
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
|
-
: '
|
|
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
|
|
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('
|
|
82
|
-
week_number_header: cn('w-
|
|
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-
|
|
83
|
+
'text-[0.8rem] select-none text-muted-foreground',
|
|
85
84
|
defaultClassNames.week_number
|
|
86
85
|
),
|
|
87
86
|
day: cn(
|
|
88
|
-
'
|
|
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(
|
|
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(
|
|
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-
|
|
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 <
|
|
120
|
+
return <ChevronLeft className={cn('size-4', className)} {...props} />
|
|
113
121
|
}
|
|
114
122
|
|
|
115
123
|
if (orientation === 'right') {
|
|
116
|
-
return <
|
|
124
|
+
return <ChevronRight className={cn('size-4', className)} {...props} />
|
|
117
125
|
}
|
|
118
126
|
|
|
119
|
-
return <
|
|
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-
|
|
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-
|
|
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
|
)}
|
package/templates/ui/card.tsx
CHANGED
|
@@ -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
|
-
|
|
5
|
-
|
|
4
|
+
function Card({
|
|
5
|
+
className,
|
|
6
|
+
size = 'default',
|
|
7
|
+
...props
|
|
8
|
+
}: React.ComponentProps<'div'> & { size?: 'default' | 'sm' }) {
|
|
9
|
+
return (
|
|
6
10
|
<div
|
|
7
|
-
|
|
8
|
-
|
|
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
|
-
|
|
16
|
-
|
|
17
|
-
<div
|
|
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
|
-
|
|
23
|
-
|
|
35
|
+
function CardTitle({ className, ...props }: React.ComponentProps<'div'>) {
|
|
36
|
+
return (
|
|
24
37
|
<div
|
|
25
|
-
|
|
26
|
-
className={cn(
|
|
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
|
-
|
|
34
|
-
|
|
35
|
-
<div
|
|
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
|
-
|
|
41
|
-
|
|
42
|
-
<div
|
|
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
|
-
|
|
48
|
-
|
|
49
|
-
<div
|
|
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 {
|
|
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
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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
|
-
|
|
158
|
-
|
|
159
|
-
const { orientation } = useCarousel()
|
|
131
|
+
function CarouselContent({ className, ...props }: React.ComponentProps<'div'>) {
|
|
132
|
+
const { carouselRef, orientation } = useCarousel()
|
|
160
133
|
|
|
161
|
-
|
|
134
|
+
return (
|
|
135
|
+
<div ref={carouselRef} className="overflow-hidden" data-slot="carousel-content">
|
|
162
136
|
<div
|
|
163
|
-
|
|
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
|
-
|
|
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
|
+
}
|