@neynar/ui 0.1.1 → 0.1.2

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 (173) hide show
  1. package/dist/components/ui/accordion.d.ts +1 -25
  2. package/dist/components/ui/accordion.d.ts.map +1 -1
  3. package/dist/components/ui/alert-dialog.d.ts +240 -46
  4. package/dist/components/ui/alert-dialog.d.ts.map +1 -1
  5. package/dist/components/ui/alert.d.ts +73 -11
  6. package/dist/components/ui/alert.d.ts.map +1 -1
  7. package/dist/components/ui/aspect-ratio.d.ts +44 -10
  8. package/dist/components/ui/aspect-ratio.d.ts.map +1 -1
  9. package/dist/components/ui/avatar.d.ts +117 -33
  10. package/dist/components/ui/avatar.d.ts.map +1 -1
  11. package/dist/components/ui/badge.d.ts +50 -71
  12. package/dist/components/ui/badge.d.ts.map +1 -1
  13. package/dist/components/ui/breadcrumb.d.ts +231 -49
  14. package/dist/components/ui/breadcrumb.d.ts.map +1 -1
  15. package/dist/components/ui/button.d.ts +189 -71
  16. package/dist/components/ui/button.d.ts.map +1 -1
  17. package/dist/components/ui/calendar.d.ts +197 -40
  18. package/dist/components/ui/calendar.d.ts.map +1 -1
  19. package/dist/components/ui/card.d.ts +7 -22
  20. package/dist/components/ui/card.d.ts.map +1 -1
  21. package/dist/components/ui/carousel.d.ts +369 -99
  22. package/dist/components/ui/carousel.d.ts.map +1 -1
  23. package/dist/components/ui/chart.d.ts.map +1 -1
  24. package/dist/components/ui/checkbox.d.ts +110 -38
  25. package/dist/components/ui/checkbox.d.ts.map +1 -1
  26. package/dist/components/ui/collapsible.d.ts +246 -61
  27. package/dist/components/ui/collapsible.d.ts.map +1 -1
  28. package/dist/components/ui/combobox.d.ts +207 -159
  29. package/dist/components/ui/combobox.d.ts.map +1 -1
  30. package/dist/components/ui/command.d.ts +336 -67
  31. package/dist/components/ui/command.d.ts.map +1 -1
  32. package/dist/components/ui/container.d.ts +159 -64
  33. package/dist/components/ui/container.d.ts.map +1 -1
  34. package/dist/components/ui/context-menu.d.ts +321 -39
  35. package/dist/components/ui/context-menu.d.ts.map +1 -1
  36. package/dist/components/ui/date-picker.d.ts +113 -86
  37. package/dist/components/ui/date-picker.d.ts.map +1 -1
  38. package/dist/components/ui/dialog.d.ts +106 -25
  39. package/dist/components/ui/dialog.d.ts.map +1 -1
  40. package/dist/components/ui/drawer.d.ts +388 -59
  41. package/dist/components/ui/drawer.d.ts.map +1 -1
  42. package/dist/components/ui/dropdown-menu.d.ts +521 -74
  43. package/dist/components/ui/dropdown-menu.d.ts.map +1 -1
  44. package/dist/components/ui/empty-state.d.ts +148 -76
  45. package/dist/components/ui/empty-state.d.ts.map +1 -1
  46. package/dist/components/ui/hover-card.d.ts +253 -34
  47. package/dist/components/ui/hover-card.d.ts.map +1 -1
  48. package/dist/components/ui/input.d.ts +143 -44
  49. package/dist/components/ui/input.d.ts.map +1 -1
  50. package/dist/components/ui/label.d.ts +0 -8
  51. package/dist/components/ui/label.d.ts.map +1 -1
  52. package/dist/components/ui/menubar.d.ts +288 -46
  53. package/dist/components/ui/menubar.d.ts.map +1 -1
  54. package/dist/components/ui/navigation-menu.d.ts +444 -127
  55. package/dist/components/ui/navigation-menu.d.ts.map +1 -1
  56. package/dist/components/ui/pagination.d.ts +342 -66
  57. package/dist/components/ui/pagination.d.ts.map +1 -1
  58. package/dist/components/ui/popover.d.ts +0 -8
  59. package/dist/components/ui/popover.d.ts.map +1 -1
  60. package/dist/components/ui/progress.d.ts +88 -30
  61. package/dist/components/ui/progress.d.ts.map +1 -1
  62. package/dist/components/ui/radio-group.d.ts +189 -45
  63. package/dist/components/ui/radio-group.d.ts.map +1 -1
  64. package/dist/components/ui/resizable.d.ts +178 -62
  65. package/dist/components/ui/resizable.d.ts.map +1 -1
  66. package/dist/components/ui/scroll-area.d.ts +180 -21
  67. package/dist/components/ui/scroll-area.d.ts.map +1 -1
  68. package/dist/components/ui/select.d.ts +382 -60
  69. package/dist/components/ui/select.d.ts.map +1 -1
  70. package/dist/components/ui/separator.d.ts +52 -39
  71. package/dist/components/ui/separator.d.ts.map +1 -1
  72. package/dist/components/ui/sheet.d.ts +144 -27
  73. package/dist/components/ui/sheet.d.ts.map +1 -1
  74. package/dist/components/ui/sidebar.d.ts +81 -31
  75. package/dist/components/ui/sidebar.d.ts.map +1 -1
  76. package/dist/components/ui/skeleton.d.ts +94 -32
  77. package/dist/components/ui/skeleton.d.ts.map +1 -1
  78. package/dist/components/ui/slider.d.ts +37 -31
  79. package/dist/components/ui/slider.d.ts.map +1 -1
  80. package/dist/components/ui/sonner.d.ts +280 -46
  81. package/dist/components/ui/sonner.d.ts.map +1 -1
  82. package/dist/components/ui/stack.d.ts +289 -148
  83. package/dist/components/ui/stack.d.ts.map +1 -1
  84. package/dist/components/ui/stories/aspect-ratio.stories.d.ts +1 -2
  85. package/dist/components/ui/stories/aspect-ratio.stories.d.ts.map +1 -1
  86. package/dist/components/ui/stories/container.stories.d.ts +2 -3
  87. package/dist/components/ui/stories/container.stories.d.ts.map +1 -1
  88. package/dist/components/ui/stories/empty-state.stories.d.ts +2 -2
  89. package/dist/components/ui/stories/scroll-area.stories.d.ts +1 -2
  90. package/dist/components/ui/stories/scroll-area.stories.d.ts.map +1 -1
  91. package/dist/components/ui/stories/stack.stories.d.ts +1 -1
  92. package/dist/components/ui/stories/text-field.stories.d.ts +7 -1
  93. package/dist/components/ui/stories/text-field.stories.d.ts.map +1 -1
  94. package/dist/components/ui/switch.d.ts +44 -38
  95. package/dist/components/ui/switch.d.ts.map +1 -1
  96. package/dist/components/ui/table.d.ts +33 -0
  97. package/dist/components/ui/table.d.ts.map +1 -1
  98. package/dist/components/ui/tabs.d.ts +4 -22
  99. package/dist/components/ui/tabs.d.ts.map +1 -1
  100. package/dist/components/ui/text-field.d.ts +170 -84
  101. package/dist/components/ui/text-field.d.ts.map +1 -1
  102. package/dist/components/ui/textarea.d.ts +106 -29
  103. package/dist/components/ui/textarea.d.ts.map +1 -1
  104. package/dist/components/ui/theme-toggle.d.ts +190 -65
  105. package/dist/components/ui/theme-toggle.d.ts.map +1 -1
  106. package/dist/components/ui/theme.d.ts +107 -23
  107. package/dist/components/ui/theme.d.ts.map +1 -1
  108. package/dist/components/ui/toggle-group.d.ts +143 -67
  109. package/dist/components/ui/toggle-group.d.ts.map +1 -1
  110. package/dist/components/ui/toggle.d.ts +118 -30
  111. package/dist/components/ui/toggle.d.ts.map +1 -1
  112. package/dist/components/ui/tooltip.d.ts +152 -28
  113. package/dist/components/ui/tooltip.d.ts.map +1 -1
  114. package/dist/components/ui/typography.d.ts +452 -134
  115. package/dist/components/ui/typography.d.ts.map +1 -1
  116. package/dist/index.js +9388 -8281
  117. package/dist/index.js.map +1 -1
  118. package/dist/tsconfig.tsbuildinfo +1 -1
  119. package/llms.txt +173 -3
  120. package/package.json +5 -2
  121. package/src/components/ui/accordion.tsx +112 -27
  122. package/src/components/ui/alert-dialog.tsx +401 -46
  123. package/src/components/ui/alert.tsx +114 -11
  124. package/src/components/ui/aspect-ratio.tsx +69 -14
  125. package/src/components/ui/avatar.tsx +179 -33
  126. package/src/components/ui/badge.tsx +74 -75
  127. package/src/components/ui/breadcrumb.tsx +335 -50
  128. package/src/components/ui/button.tsx +198 -90
  129. package/src/components/ui/calendar.tsx +867 -43
  130. package/src/components/ui/card.tsx +140 -33
  131. package/src/components/ui/carousel.tsx +529 -98
  132. package/src/components/ui/chart.tsx +222 -1
  133. package/src/components/ui/checkbox.tsx +176 -38
  134. package/src/components/ui/collapsible.tsx +321 -67
  135. package/src/components/ui/combobox.tsx +284 -83
  136. package/src/components/ui/command.tsx +527 -67
  137. package/src/components/ui/container.tsx +217 -65
  138. package/src/components/ui/context-menu.tsx +716 -51
  139. package/src/components/ui/date-picker.tsx +228 -38
  140. package/src/components/ui/dialog.tsx +270 -33
  141. package/src/components/ui/drawer.tsx +546 -67
  142. package/src/components/ui/dropdown-menu.tsx +657 -74
  143. package/src/components/ui/empty-state.tsx +241 -82
  144. package/src/components/ui/hover-card.tsx +328 -39
  145. package/src/components/ui/input.tsx +207 -44
  146. package/src/components/ui/label.tsx +98 -8
  147. package/src/components/ui/menubar.tsx +587 -54
  148. package/src/components/ui/navigation-menu.tsx +557 -128
  149. package/src/components/ui/pagination.tsx +561 -79
  150. package/src/components/ui/popover.tsx +119 -8
  151. package/src/components/ui/progress.tsx +131 -29
  152. package/src/components/ui/radio-group.tsx +260 -51
  153. package/src/components/ui/resizable.tsx +289 -63
  154. package/src/components/ui/scroll-area.tsx +377 -66
  155. package/src/components/ui/select.tsx +545 -60
  156. package/src/components/ui/separator.tsx +146 -40
  157. package/src/components/ui/sheet.tsx +348 -31
  158. package/src/components/ui/sidebar.tsx +471 -29
  159. package/src/components/ui/skeleton.tsx +114 -32
  160. package/src/components/ui/slider.tsx +77 -31
  161. package/src/components/ui/sonner.tsx +574 -46
  162. package/src/components/ui/stack.tsx +423 -101
  163. package/src/components/ui/switch.tsx +78 -39
  164. package/src/components/ui/table.tsx +170 -4
  165. package/src/components/ui/tabs.tsx +108 -22
  166. package/src/components/ui/text-field.tsx +226 -81
  167. package/src/components/ui/textarea.tsx +180 -29
  168. package/src/components/ui/theme-toggle.tsx +313 -65
  169. package/src/components/ui/theme.tsx +117 -23
  170. package/src/components/ui/toggle-group.tsx +280 -69
  171. package/src/components/ui/toggle.tsx +124 -35
  172. package/src/components/ui/tooltip.tsx +239 -29
  173. package/src/components/ui/typography.tsx +1115 -165
@@ -8,24 +8,238 @@ import { ArrowLeft, ArrowRight } from "lucide-react";
8
8
  import { cn } from "@/lib/utils";
9
9
  import { Button } from "@/components/ui/button";
10
10
 
11
+ /** Embla Carousel API instance type for programmatic control */
11
12
  type CarouselApi = UseEmblaCarouselType[1];
13
+
14
+ /** Parameters for the useEmblaCarousel hook */
12
15
  type UseCarouselParameters = Parameters<typeof useEmblaCarousel>;
16
+
17
+ /** Embla Carousel configuration options */
13
18
  type CarouselOptions = UseCarouselParameters[0];
19
+
20
+ /** Array of Embla Carousel plugins */
14
21
  type CarouselPlugin = UseCarouselParameters[1];
15
22
 
23
+ /**
24
+ * Props for Carousel component (Documentation only - NOT used in component implementation)
25
+ * These types are for documentation generation and should not replace embla-carousel inferred types
26
+ */
27
+ // eslint-disable-next-line unused-imports/no-unused-vars
28
+ type CarouselDocsProps = {
29
+ /**
30
+ * Embla Carousel configuration options
31
+ *
32
+ * Supports all Embla options including:
33
+ * - `active`: Enable/disable the carousel (default: true)
34
+ * - `align`: Slide alignment - "start", "center", "end", or custom function (default: "center")
35
+ * - `axis`: Scroll direction - "x" for horizontal, "y" for vertical (default: "x")
36
+ * - `breakpoints`: Responsive configuration object with media queries
37
+ * - `container`: Custom container element selector or HTMLElement
38
+ * - `containScroll`: Handle empty space - false, "trimSnaps", "keepSnaps" (default: "trimSnaps")
39
+ * - `direction`: Content direction - "ltr" or "rtl" (default: "ltr")
40
+ * - `dragFree`: Enable momentum scrolling (default: false)
41
+ * - `dragThreshold`: Drag threshold in pixels (default: 10)
42
+ * - `duration`: Scroll duration for API methods, 20-60 recommended (default: 25)
43
+ * - `inViewThreshold`: Intersection Observer threshold (default: 0)
44
+ * - `loop`: Enable infinite looping (default: false)
45
+ * - `skipSnaps`: Allow skipping snaps on vigorous drag (default: false)
46
+ * - `slides`: Custom slide elements selector or HTMLElement array
47
+ * - `slidesToScroll`: Number of slides to scroll or "auto" (default: 1)
48
+ * - `startIndex`: Initial scroll snap index (default: 0)
49
+ * - `watchDrag`: Enable drag interactions (default: true)
50
+ * - `watchFocus`: Enable focus-based scrolling (default: true)
51
+ * - `watchResize`: Enable auto-reinit on resize (default: true)
52
+ * - `watchSlides`: Enable auto-reinit when slides change (default: true)
53
+ * @default {}
54
+ */
55
+ opts?: CarouselOptions;
56
+
57
+ /**
58
+ * Array of Embla Carousel plugins for extended functionality
59
+ *
60
+ * Common plugins include:
61
+ * - `Autoplay`: Automatic slide progression
62
+ * - `AutoScroll`: Continuous smooth scrolling
63
+ * - `ClassNames`: CSS class management based on carousel state
64
+ * - `WheelGestures`: Mouse wheel navigation
65
+ * - `Fade`: Fade transition effects
66
+ * @default undefined
67
+ */
68
+ plugins?: CarouselPlugin;
69
+
70
+ /**
71
+ * Carousel orientation/layout direction
72
+ *
73
+ * - "horizontal": Default horizontal layout with left/right navigation
74
+ * - "vertical": Vertical layout with up/down navigation
75
+ * @default "horizontal"
76
+ */
77
+ orientation?: "horizontal" | "vertical";
78
+
79
+ /**
80
+ * Callback to receive the Embla Carousel API instance
81
+ *
82
+ * The API provides methods for programmatic control:
83
+ * - Navigation: `scrollNext()`, `scrollPrev()`, `scrollTo(index)`
84
+ * - State: `selectedScrollSnap()`, `canScrollNext()`, `canScrollPrev()`
85
+ * - Events: `on(event, callback)`, `off(event, callback)`
86
+ * - Elements: `slideNodes()`, `rootNode()`, `containerNode()`
87
+ * @param api - The Embla Carousel API instance
88
+ */
89
+ setApi?: (api: CarouselApi) => void;
90
+
91
+ /** Additional CSS classes for styling */
92
+ className?: string;
93
+
94
+ /** Carousel content and navigation elements */
95
+ children?: React.ReactNode;
96
+ } & Omit<React.ComponentProps<"div">, "className" | "children" | "orientation">;
97
+
98
+ /**
99
+ * Props for CarouselContent component (Documentation only - NOT used in component implementation)
100
+ * These types are for documentation generation and should not replace inferred types
101
+ */
102
+ // eslint-disable-next-line unused-imports/no-unused-vars
103
+ type CarouselContentDocsProps = {
104
+ /**
105
+ * Additional CSS classes for custom spacing and styling
106
+ *
107
+ * Common patterns:
108
+ * - Horizontal: `-ml-2 md:-ml-4` for negative margin spacing
109
+ * - Vertical: `-mt-4 h-[300px]` for vertical layout with fixed height
110
+ * - Gap control: Adjust negative margins to control slide spacing
111
+ */
112
+ className?: string;
113
+
114
+ /** CarouselItem components and other slide content */
115
+ children?: React.ReactNode;
116
+ } & Omit<React.HTMLAttributes<HTMLDivElement>, "className" | "children">;
117
+
118
+ /**
119
+ * Props for CarouselItem component (Documentation only - NOT used in component implementation)
120
+ * These types are for documentation generation and should not replace inferred types
121
+ */
122
+ // eslint-disable-next-line unused-imports/no-unused-vars
123
+ type CarouselItemDocsProps = {
124
+ /**
125
+ * Additional CSS classes for sizing, spacing, and styling
126
+ *
127
+ * Common sizing patterns:
128
+ * - `basis-full`: Full width slide (default)
129
+ * - `basis-1/2`: Half width (2 slides visible)
130
+ * - `basis-1/3`: Third width (3 slides visible)
131
+ * - `basis-auto`: Auto-sizing based on content
132
+ * - `md:basis-1/2 lg:basis-1/3`: Responsive sizing
133
+ *
134
+ * Spacing patterns:
135
+ * - `pl-2 md:pl-4`: Left padding (horizontal carousels)
136
+ * - `pt-4`: Top padding (vertical carousels)
137
+ */
138
+ className?: string;
139
+
140
+ /** Content to display within the slide */
141
+ children?: React.ReactNode;
142
+ } & Omit<React.HTMLAttributes<HTMLDivElement>, "className" | "children">;
143
+
144
+ /**
145
+ * Props for CarouselPrevious component (Documentation only - NOT used in component implementation)
146
+ * These types are for documentation generation and should not replace inferred types
147
+ */
148
+ // eslint-disable-next-line unused-imports/no-unused-vars
149
+ type CarouselPreviousDocsProps = {
150
+ /**
151
+ * Additional CSS classes for custom positioning and styling
152
+ *
153
+ * Default positioning:
154
+ * - Horizontal: `top-1/2 -left-12 -translate-y-1/2`
155
+ * - Vertical: `-top-12 left-1/2 -translate-x-1/2 rotate-90`
156
+ */
157
+ className?: string;
158
+
159
+ /**
160
+ * Button variant styling
161
+ * @default "outline"
162
+ */
163
+ variant?:
164
+ | "default"
165
+ | "destructive"
166
+ | "outline"
167
+ | "secondary"
168
+ | "ghost"
169
+ | "link";
170
+
171
+ /**
172
+ * Button size
173
+ * @default "icon"
174
+ */
175
+ size?: "default" | "sm" | "lg" | "icon";
176
+ } & Omit<
177
+ React.ButtonHTMLAttributes<HTMLButtonElement>,
178
+ "className" | "variant" | "size"
179
+ >;
180
+
181
+ /**
182
+ * Props for CarouselNext component (Documentation only - NOT used in component implementation)
183
+ * These types are for documentation generation and should not replace inferred types
184
+ */
185
+ // eslint-disable-next-line unused-imports/no-unused-vars
186
+ type CarouselNextDocsProps = {
187
+ /**
188
+ * Additional CSS classes for custom positioning and styling
189
+ *
190
+ * Default positioning:
191
+ * - Horizontal: `top-1/2 -right-12 -translate-y-1/2`
192
+ * - Vertical: `-bottom-12 left-1/2 -translate-x-1/2 rotate-90`
193
+ */
194
+ className?: string;
195
+
196
+ /**
197
+ * Button variant styling
198
+ * @default "outline"
199
+ */
200
+ variant?:
201
+ | "default"
202
+ | "destructive"
203
+ | "outline"
204
+ | "secondary"
205
+ | "ghost"
206
+ | "link";
207
+
208
+ /**
209
+ * Button size
210
+ * @default "icon"
211
+ */
212
+ size?: "default" | "sm" | "lg" | "icon";
213
+ } & Omit<
214
+ React.ButtonHTMLAttributes<HTMLButtonElement>,
215
+ "className" | "variant" | "size"
216
+ >;
217
+
218
+ /** Props for Carousel component (used in component implementation) */
16
219
  type CarouselProps = {
220
+ /** Embla Carousel configuration options */
17
221
  opts?: CarouselOptions;
222
+ /** Array of Embla Carousel plugins for extended functionality */
18
223
  plugins?: CarouselPlugin;
224
+ /** Carousel orientation/layout direction */
19
225
  orientation?: "horizontal" | "vertical";
226
+ /** Callback to receive the Embla Carousel API instance */
20
227
  setApi?: (api: CarouselApi) => void;
21
228
  };
22
229
 
230
+ /** Props for the carousel context provider */
23
231
  type CarouselContextProps = {
232
+ /** Ref for the Embla carousel viewport element */
24
233
  carouselRef: ReturnType<typeof useEmblaCarousel>[0];
234
+ /** Embla Carousel API instance for programmatic control */
25
235
  api: ReturnType<typeof useEmblaCarousel>[1];
236
+ /** Function to scroll to the previous slide */
26
237
  scrollPrev: () => void;
238
+ /** Function to scroll to the next slide */
27
239
  scrollNext: () => void;
240
+ /** Whether the carousel can scroll to previous slide */
28
241
  canScrollPrev: boolean;
242
+ /** Whether the carousel can scroll to next slide */
29
243
  canScrollNext: boolean;
30
244
  } & CarouselProps;
31
245
 
@@ -84,15 +298,11 @@ function useCarousel() {
84
298
  *
85
299
  * The Carousel component provides a touch-friendly, keyboard-accessible way to
86
300
  * browse through multiple items. Built on Embla Carousel, it supports various
87
- * configurations including autoplay, loop, drag scrolling, and both horizontal
88
- * and vertical orientations.
301
+ * configurations including autoplay, loop, drag scrolling, infinite scroll,
302
+ * momentum scrolling, and both horizontal and vertical orientations.
89
303
  *
90
- * @param opts - Embla Carousel configuration options (align, loop, etc.)
91
- * @param plugins - Array of Embla Carousel plugins (autoplay, etc.)
92
- * @param orientation - Layout direction: "horizontal" or "vertical" (default: "horizontal")
93
- * @param setApi - Callback to receive the carousel API instance
94
- * @param className - Additional CSS classes
95
- * @param children - Carousel content (typically CarouselContent and navigation buttons)
304
+ * Features include responsive breakpoints, plugin system, smooth animations,
305
+ * focus management, RTL support, and extensive customization options.
96
306
  *
97
307
  * @example
98
308
  * ```tsx
@@ -112,9 +322,16 @@ function useCarousel() {
112
322
  *
113
323
  * @example
114
324
  * ```tsx
115
- * // Multi-item responsive carousel
325
+ * // Multi-item responsive carousel with custom spacing
116
326
  * <Carousel
117
- * opts={{ align: "start", loop: true }}
327
+ * opts={{
328
+ * align: "start",
329
+ * loop: true,
330
+ * slidesToScroll: "auto",
331
+ * breakpoints: {
332
+ * "(min-width: 768px)": { slidesToScroll: 2 }
333
+ * }
334
+ * }}
118
335
  * className="w-full"
119
336
  * >
120
337
  * <CarouselContent className="-ml-2 md:-ml-4">
@@ -136,12 +353,13 @@ function useCarousel() {
136
353
  *
137
354
  * @example
138
355
  * ```tsx
139
- * // Vertical carousel with autoplay
356
+ * // Vertical carousel with autoplay plugin
140
357
  * import Autoplay from "embla-carousel-autoplay";
141
358
  *
142
359
  * <Carousel
143
360
  * orientation="vertical"
144
- * plugins={[Autoplay({ delay: 3000, stopOnInteraction: true })]}
361
+ * opts={{ loop: true, align: "center" }}
362
+ * plugins={[Autoplay({ delay: 3000, stopOnInteraction: true, stopOnMouseEnter: true })]}
145
363
  * className="h-[400px]"
146
364
  * >
147
365
  * <CarouselContent className="h-full">
@@ -159,47 +377,121 @@ function useCarousel() {
159
377
  *
160
378
  * @example
161
379
  * ```tsx
162
- * // Controlled carousel with custom indicators
380
+ * // Controlled carousel with custom indicators and API access
381
+ * import { useState, useEffect } from "react";
382
+ *
163
383
  * function ControlledCarousel() {
164
384
  * const [api, setApi] = useState<CarouselApi>();
165
385
  * const [current, setCurrent] = useState(0);
386
+ * const [count, setCount] = useState(0);
166
387
  *
167
388
  * useEffect(() => {
168
389
  * if (!api) return;
169
- * setCurrent(api.selectedScrollSnap());
170
- * api.on('select', () => setCurrent(api.selectedScrollSnap()));
390
+ *
391
+ * setCount(api.scrollSnapList().length);
392
+ * setCurrent(api.selectedScrollSnap() + 1);
393
+ *
394
+ * api.on('select', () => {
395
+ * setCurrent(api.selectedScrollSnap() + 1);
396
+ * });
171
397
  * }, [api]);
172
398
  *
173
399
  * return (
174
- * <div>
175
- * <Carousel setApi={setApi}>
176
- * <CarouselContent>...</CarouselContent>
400
+ * <div className="space-y-4">
401
+ * <Carousel setApi={setApi} opts={{ loop: true }}>
402
+ * <CarouselContent>
403
+ * {slides.map((slide, index) => (
404
+ * <CarouselItem key={index}>{slide.content}</CarouselItem>
405
+ * ))}
406
+ * </CarouselContent>
407
+ * <CarouselPrevious />
408
+ * <CarouselNext />
177
409
  * </Carousel>
178
- * <div className="flex justify-center gap-2 mt-4">
179
- * {Array.from({ length: 5 }).map((_, i) => (
410
+ *
411
+ * // Custom indicators
412
+ * <div className="flex justify-center gap-2">
413
+ * {Array.from({ length: count }).map((_, i) => (
180
414
  * <button
181
415
  * key={i}
182
- * className={current === i ? "bg-primary" : "bg-muted"}
416
+ * className={cn(
417
+ * "w-2 h-2 rounded-full transition-colors",
418
+ * current === i + 1 ? "bg-primary" : "bg-muted"
419
+ * )}
183
420
  * onClick={() => api?.scrollTo(i)}
184
421
  * />
185
422
  * ))}
186
423
  * </div>
424
+ *
425
+ * <div className="text-center text-sm text-muted-foreground">
426
+ * Slide {current} of {count}
427
+ * </div>
187
428
  * </div>
188
429
  * );
189
430
  * }
190
431
  * ```
191
432
  *
433
+ * @example
434
+ * ```tsx
435
+ * // Momentum scrolling carousel with drag-free mode
436
+ * <Carousel
437
+ * opts={{
438
+ * dragFree: true,
439
+ * containScroll: false,
440
+ * skipSnaps: true
441
+ * }}
442
+ * className="w-full"
443
+ * >
444
+ * <CarouselContent>
445
+ * {items.map((item, index) => (
446
+ * <CarouselItem key={index} className="basis-auto">
447
+ * <div className="w-32 h-32 bg-muted rounded-lg" />
448
+ * </CarouselItem>
449
+ * ))}
450
+ * </CarouselContent>
451
+ * </Carousel>
452
+ * ```
453
+ *
454
+ * @example
455
+ * ```tsx
456
+ * // Breakpoint-responsive carousel that disables on larger screens
457
+ * <Carousel
458
+ * opts={{
459
+ * active: true,
460
+ * breakpoints: {
461
+ * "(min-width: 768px)": { active: false }
462
+ * }
463
+ * }}
464
+ * className="md:hidden"
465
+ * >
466
+ * <CarouselContent>
467
+ * {mobileItems.map((item, index) => (
468
+ * <CarouselItem key={index}>{item}</CarouselItem>
469
+ * ))}
470
+ * </CarouselContent>
471
+ * <CarouselPrevious />
472
+ * <CarouselNext />
473
+ * </Carousel>
474
+ * ```
475
+ *
192
476
  * @accessibility
193
- * - Keyboard navigation with arrow keys and tab focus
194
- * - Touch/swipe gestures and mouse drag support
195
- * - Screen reader announcements for slide changes
196
- * - ARIA roles and labels for navigation elements
197
- * - Focus management and visible focus indicators
198
- * - Respects reduced motion preferences
199
- * - RTL layout support
477
+ * - **Keyboard Navigation**: Arrow keys for slide navigation, Tab for focus management
478
+ * - **Touch/Drag Support**: Multi-touch gestures, mouse drag, momentum scrolling
479
+ * - **Screen Reader**: ARIA roles, labels, and announcements for slide changes
480
+ * - **Focus Management**: Automatic focus handling, visible focus indicators
481
+ * - **Motion**: Respects `prefers-reduced-motion` for accessibility
482
+ * - **RTL Support**: Right-to-left layout support with `direction: "rtl"` option
483
+ * - **High Contrast**: Proper color contrast for navigation elements
484
+ *
485
+ * **Keyboard Shortcuts:**
486
+ * - `←/→` or `↑/↓`: Navigate slides (based on orientation)
487
+ * - `Home`: Go to first slide
488
+ * - `End`: Go to last slide
489
+ * - `Tab`: Focus navigation elements
200
490
  *
201
491
  * @see {@link https://ui.shadcn.com/docs/components/carousel} shadcn/ui carousel documentation
202
492
  * @see {@link https://www.embla-carousel.com/} Embla Carousel documentation
493
+ * @see {@link https://www.embla-carousel.com/api/options/} Embla options reference
494
+ * @see {@link https://www.embla-carousel.com/plugins/} Available Embla plugins
203
495
  * @see {@link useCarousel} Hook for accessing carousel controls
204
496
  * @see {@link CarouselContent} Container for carousel items
205
497
  * @see {@link CarouselItem} Individual carousel slide
@@ -215,7 +507,7 @@ function Carousel({
215
507
  className,
216
508
  children,
217
509
  ...props
218
- }: React.ComponentProps<"div"> & CarouselProps) {
510
+ }: CarouselProps & React.ComponentProps<"div">) {
219
511
  const [carouselRef, api] = useEmblaCarousel(
220
512
  {
221
513
  ...opts,
@@ -294,15 +586,21 @@ function Carousel({
294
586
  );
295
587
  }
296
588
 
589
+ /** Props for CarouselContent component (used in component implementation) */
590
+ type CarouselContentProps = {
591
+ /** Additional CSS classes for custom spacing and styling */
592
+ className?: string;
593
+ /** CarouselItem components and other slide content */
594
+ children?: React.ReactNode;
595
+ } & Omit<React.HTMLAttributes<HTMLDivElement>, "className" | "children">;
596
+
297
597
  /**
298
598
  * Container component for carousel items that handles the scrolling viewport
299
599
  *
300
600
  * Wraps all carousel items and manages the scrollable area. This component
301
- * must be a direct child of Carousel and handles orientation-specific layouts
302
- * and overflow behavior.
303
- *
304
- * @param className - Additional CSS classes for custom spacing and styling
305
- * @param children - CarouselItem components
601
+ * must be a direct child of Carousel and handles orientation-specific layouts,
602
+ * overflow behavior, and slide spacing. The outer div provides overflow clipping
603
+ * while the inner div contains the flex layout for slides.
306
604
  *
307
605
  * @example
308
606
  * ```tsx
@@ -316,32 +614,55 @@ function Carousel({
316
614
  *
317
615
  * @example
318
616
  * ```tsx
319
- * // With custom spacing (horizontal)
617
+ * // Multi-item carousel with responsive spacing
320
618
  * <CarouselContent className="-ml-2 md:-ml-4">
321
- * <CarouselItem className="pl-2 md:pl-4">Slide 1</CarouselItem>
322
- * <CarouselItem className="pl-2 md:pl-4">Slide 2</CarouselItem>
619
+ * <CarouselItem className="pl-2 md:pl-4 md:basis-1/2 lg:basis-1/3">
620
+ * <Card>Product 1</Card>
621
+ * </CarouselItem>
622
+ * <CarouselItem className="pl-2 md:pl-4 md:basis-1/2 lg:basis-1/3">
623
+ * <Card>Product 2</Card>
624
+ * </CarouselItem>
323
625
  * </CarouselContent>
324
626
  * ```
325
627
  *
326
628
  * @example
327
629
  * ```tsx
328
- * // Vertical orientation spacing
630
+ * // Vertical orientation with custom height
329
631
  * <CarouselContent className="-mt-4 h-[300px]">
330
- * <CarouselItem className="pt-4">Slide 1</CarouselItem>
331
- * <CarouselItem className="pt-4">Slide 2</CarouselItem>
632
+ * <CarouselItem className="pt-4 basis-1/2">
633
+ * <div className="h-full bg-muted rounded-lg">Slide 1</div>
634
+ * </CarouselItem>
635
+ * <CarouselItem className="pt-4 basis-1/2">
636
+ * <div className="h-full bg-muted rounded-lg">Slide 2</div>
637
+ * </CarouselItem>
638
+ * </CarouselContent>
639
+ * ```
640
+ *
641
+ * @example
642
+ * ```tsx
643
+ * // Custom slide spacing with CSS variables
644
+ * <CarouselContent
645
+ * className="-ml-4"
646
+ * style={{ '--slide-spacing': '1rem' } as React.CSSProperties}
647
+ * >
648
+ * <CarouselItem className="pl-4">
649
+ * Content with custom spacing
650
+ * </CarouselItem>
332
651
  * </CarouselContent>
333
652
  * ```
334
653
  *
335
654
  * @accessibility
336
655
  * - Provides scrollable container with proper overflow handling
337
656
  * - Maintains responsive layout for horizontal/vertical orientations
338
- * - Works with screen readers for content navigation
657
+ * - Supports screen reader navigation through slide content
658
+ * - Preserves focus management within slides
659
+ * - Uses semantic HTML structure for assistive technologies
339
660
  *
340
661
  * @see {@link Carousel} Main carousel component
341
662
  * @see {@link CarouselItem} Individual carousel slides
342
663
  * @since 1.0.0
343
664
  */
344
- function CarouselContent({ className, ...props }: React.ComponentProps<"div">) {
665
+ function CarouselContent({ className, ...props }: CarouselContentProps) {
345
666
  const { carouselRef, orientation } = useCarousel();
346
667
 
347
668
  return (
@@ -362,21 +683,27 @@ function CarouselContent({ className, ...props }: React.ComponentProps<"div">) {
362
683
  );
363
684
  }
364
685
 
686
+ /** Props for CarouselItem component (used in component implementation) */
687
+ type CarouselItemProps = {
688
+ /** Additional CSS classes for sizing, spacing, and styling */
689
+ className?: string;
690
+ /** Content to display within the slide */
691
+ children?: React.ReactNode;
692
+ } & Omit<React.HTMLAttributes<HTMLDivElement>, "className" | "children">;
693
+
365
694
  /**
366
695
  * Individual slide/item component within the carousel
367
696
  *
368
697
  * Represents a single slide in the carousel that can contain any content.
369
698
  * Automatically handles sizing, spacing, and orientation-specific layouts
370
- * based on the parent carousel configuration.
371
- *
372
- * @param className - Additional CSS classes for sizing (basis-*) and spacing
373
- * @param children - Content to display within the slide
699
+ * based on the parent carousel configuration. Each slide is a flex item
700
+ * with configurable basis for responsive layouts.
374
701
  *
375
702
  * @example
376
703
  * ```tsx
377
704
  * // Basic slide with content
378
705
  * <CarouselItem>
379
- * <div className="p-6">
706
+ * <div className="p-6 bg-muted rounded-lg">
380
707
  * <h3 className="text-lg font-semibold">Slide Title</h3>
381
708
  * <p className="text-muted-foreground">Slide description</p>
382
709
  * </div>
@@ -385,46 +712,74 @@ function CarouselContent({ className, ...props }: React.ComponentProps<"div">) {
385
712
  *
386
713
  * @example
387
714
  * ```tsx
388
- * // Card-based slide
715
+ * // Card-based slide with structured content
389
716
  * <CarouselItem>
390
- * <Card>
717
+ * <Card className="h-full">
391
718
  * <CardHeader>
392
719
  * <CardTitle>Product Name</CardTitle>
720
+ * <CardDescription>Product category</CardDescription>
393
721
  * </CardHeader>
394
722
  * <CardContent>
395
- * <img src="product.jpg" alt="Product" className="w-full" />
396
- * <p className="mt-2">$99.99</p>
723
+ * <img src="product.jpg" alt="Product" className="w-full aspect-square object-cover" />
724
+ * <p className="mt-2 text-2xl font-bold">$99.99</p>
397
725
  * </CardContent>
726
+ * <CardFooter>
727
+ * <Button className="w-full">Add to Cart</Button>
728
+ * </CardFooter>
398
729
  * </Card>
399
730
  * </CarouselItem>
400
731
  * ```
401
732
  *
402
733
  * @example
403
734
  * ```tsx
404
- * // Responsive sizing - multiple items visible
405
- * <CarouselItem className="md:basis-1/2 lg:basis-1/3">
406
- * <div className="aspect-square bg-muted rounded-lg" />
735
+ * // Responsive multi-item carousel
736
+ * <CarouselItem className="pl-4 basis-full sm:basis-1/2 lg:basis-1/3">
737
+ * <div className="aspect-square bg-gradient-to-br from-blue-400 to-purple-600 rounded-lg p-6 text-white">
738
+ * <h4 className="font-semibold">Feature {index + 1}</h4>
739
+ * <p className="text-sm opacity-90">Description text</p>
740
+ * </div>
741
+ * </CarouselItem>
742
+ * ```
743
+ *
744
+ * @example
745
+ * ```tsx
746
+ * // Auto-sized slides for variable content
747
+ * <CarouselItem className="basis-auto">
748
+ * <Badge variant="secondary" className="text-nowrap px-4 py-2">
749
+ * {tag.label}
750
+ * </Badge>
407
751
  * </CarouselItem>
408
752
  * ```
409
753
  *
410
754
  * @example
411
755
  * ```tsx
412
- * // Custom sizing with fixed width
756
+ * // Image gallery slide with aspect ratio
413
757
  * <CarouselItem className="basis-4/5">
414
- * <div className="w-full h-48 bg-gradient-to-r from-blue-500 to-purple-600" />
758
+ * <div className="relative aspect-video bg-muted rounded-lg overflow-hidden">
759
+ * <img
760
+ * src={image.src}
761
+ * alt={image.alt}
762
+ * className="object-cover w-full h-full"
763
+ * />
764
+ * <div className="absolute inset-0 bg-black/20 flex items-end p-4">
765
+ * <h5 className="text-white font-medium">{image.title}</h5>
766
+ * </div>
767
+ * </div>
415
768
  * </CarouselItem>
416
769
  * ```
417
770
  *
418
771
  * @accessibility
419
- * - Labeled as a slide with proper ARIA role for screen readers
420
- * - Maintains focus behavior and keyboard navigation
421
- * - Preserves content structure for assistive technologies
772
+ * - **ARIA Role**: Labeled as "slide" with proper role for screen readers
773
+ * - **Focus Management**: Maintains focus behavior and keyboard navigation
774
+ * - **Content Structure**: Preserves semantic structure for assistive technologies
775
+ * - **Interactive Elements**: Supports focusable elements within slides
776
+ * - **Screen Reader**: Announces slide position and content appropriately
422
777
  *
423
778
  * @see {@link Carousel} Main carousel component
424
779
  * @see {@link CarouselContent} Container for carousel items
425
780
  * @since 1.0.0
426
781
  */
427
- function CarouselItem({ className, ...props }: React.ComponentProps<"div">) {
782
+ function CarouselItem({ className, ...props }: CarouselItemProps) {
428
783
  const { orientation } = useCarousel();
429
784
 
430
785
  return (
@@ -442,20 +797,28 @@ function CarouselItem({ className, ...props }: React.ComponentProps<"div">) {
442
797
  );
443
798
  }
444
799
 
800
+ /** Props for CarouselPrevious component (used in component implementation) */
801
+ type CarouselPreviousProps = {
802
+ /** Additional CSS classes for custom positioning and styling */
803
+ className?: string;
804
+ /** Button variant styling */
805
+ variant?: React.ComponentProps<typeof Button>["variant"];
806
+ /** Button size */
807
+ size?: React.ComponentProps<typeof Button>["size"];
808
+ } & Omit<React.ComponentProps<typeof Button>, "className" | "variant" | "size">;
809
+
445
810
  /**
446
811
  * Navigation button to go to the previous carousel slide
447
812
  *
448
813
  * Renders a previous navigation button that automatically handles disabled
449
- * states when at the beginning of the carousel. Supports both horizontal
450
- * and vertical orientations with appropriate positioning.
451
- *
452
- * @param className - Additional CSS classes for custom positioning and styling
453
- * @param variant - Button variant (default: "outline")
454
- * @param size - Button size (default: "icon")
814
+ * states when at the beginning of the carousel (unless loop is enabled).
815
+ * Supports both horizontal and vertical orientations with appropriate
816
+ * positioning and icon rotation. Integrates with the carousel context
817
+ * to provide seamless navigation.
455
818
  *
456
819
  * @example
457
820
  * ```tsx
458
- * // Basic usage
821
+ * // Basic usage with default styling
459
822
  * <Carousel>
460
823
  * <CarouselContent>
461
824
  * <CarouselItem>Slide 1</CarouselItem>
@@ -468,9 +831,9 @@ function CarouselItem({ className, ...props }: React.ComponentProps<"div">) {
468
831
  *
469
832
  * @example
470
833
  * ```tsx
471
- * // Custom styling
834
+ * // Custom positioned button
472
835
  * <CarouselPrevious
473
- * className="-left-8 bg-background shadow-md"
836
+ * className="-left-8 bg-background shadow-md hover:shadow-lg"
474
837
  * variant="ghost"
475
838
  * size="sm"
476
839
  * />
@@ -478,20 +841,47 @@ function CarouselItem({ className, ...props }: React.ComponentProps<"div">) {
478
841
  *
479
842
  * @example
480
843
  * ```tsx
481
- * // Vertical carousel positioning
482
- * <Carousel orientation="vertical">
844
+ * // Vertical carousel with rotated icons
845
+ * <Carousel orientation="vertical" className="h-[400px]">
483
846
  * <CarouselContent>...</CarouselContent>
484
- * <CarouselPrevious />
485
- * <CarouselNext />
847
+ * <CarouselPrevious className="-top-8" />
848
+ * <CarouselNext className="-bottom-8" />
486
849
  * </Carousel>
487
850
  * ```
488
851
  *
852
+ * @example
853
+ * ```tsx
854
+ * // Inside carousel bounds positioning
855
+ * <div className="relative">
856
+ * <Carousel>
857
+ * <CarouselContent>...</CarouselContent>
858
+ * <CarouselPrevious className="absolute left-4 top-1/2 -translate-y-1/2 z-10" />
859
+ * <CarouselNext className="absolute right-4 top-1/2 -translate-y-1/2 z-10" />
860
+ * </Carousel>
861
+ * </div>
862
+ * ```
863
+ *
864
+ * @example
865
+ * ```tsx
866
+ * // Custom button content and accessibility
867
+ * <CarouselPrevious
868
+ * variant="secondary"
869
+ * className="w-auto px-4"
870
+ * aria-label="Go to previous product"
871
+ * >
872
+ * <ArrowLeft className="w-4 h-4 mr-2" />
873
+ * Previous
874
+ * </CarouselPrevious>
875
+ * ```
876
+ *
489
877
  * @accessibility
490
- * - Keyboard accessible with proper focus management
491
- * - Screen reader label "Previous slide" for context
492
- * - Automatically disabled when cannot scroll further
493
- * - High contrast focus indicators
494
- * - Supports reduced motion preferences
878
+ * - **Keyboard Navigation**: Accessible via Tab and Enter/Space
879
+ * - **Screen Reader**: Built-in "Previous slide" label with sr-only text
880
+ * - **Disabled State**: Automatically disabled when cannot scroll further
881
+ * - **Focus Indicators**: High contrast focus ring for keyboard navigation
882
+ * - **Motion**: Respects `prefers-reduced-motion` for animations
883
+ * - **Touch**: Large enough touch target (44px minimum) for mobile accessibility
884
+ * - **Icon**: ArrowLeft icon rotated appropriately for vertical orientation
495
885
  *
496
886
  * @see {@link Carousel} Main carousel component
497
887
  * @see {@link CarouselNext} Next navigation button
@@ -503,7 +893,7 @@ function CarouselPrevious({
503
893
  variant = "outline",
504
894
  size = "icon",
505
895
  ...props
506
- }: React.ComponentProps<typeof Button>) {
896
+ }: CarouselPreviousProps) {
507
897
  const { orientation, scrollPrev, canScrollPrev } = useCarousel();
508
898
 
509
899
  return (
@@ -528,20 +918,28 @@ function CarouselPrevious({
528
918
  );
529
919
  }
530
920
 
921
+ /** Props for CarouselNext component (used in component implementation) */
922
+ type CarouselNextProps = {
923
+ /** Additional CSS classes for custom positioning and styling */
924
+ className?: string;
925
+ /** Button variant styling */
926
+ variant?: React.ComponentProps<typeof Button>["variant"];
927
+ /** Button size */
928
+ size?: React.ComponentProps<typeof Button>["size"];
929
+ } & Omit<React.ComponentProps<typeof Button>, "className" | "variant" | "size">;
930
+
531
931
  /**
532
932
  * Navigation button to go to the next carousel slide
533
933
  *
534
934
  * Renders a next navigation button that automatically handles disabled
535
- * states when at the end of the carousel. Supports both horizontal
536
- * and vertical orientations with appropriate positioning.
537
- *
538
- * @param className - Additional CSS classes for custom positioning and styling
539
- * @param variant - Button variant (default: "outline")
540
- * @param size - Button size (default: "icon")
935
+ * states when at the end of the carousel (unless loop is enabled).
936
+ * Supports both horizontal and vertical orientations with appropriate
937
+ * positioning and icon rotation. Integrates with the carousel context
938
+ * to provide seamless navigation.
541
939
  *
542
940
  * @example
543
941
  * ```tsx
544
- * // Basic usage
942
+ * // Basic usage with default styling
545
943
  * <Carousel>
546
944
  * <CarouselContent>
547
945
  * <CarouselItem>Slide 1</CarouselItem>
@@ -554,9 +952,9 @@ function CarouselPrevious({
554
952
  *
555
953
  * @example
556
954
  * ```tsx
557
- * // Custom styling
955
+ * // Custom positioned button
558
956
  * <CarouselNext
559
- * className="-right-8 bg-background shadow-md"
957
+ * className="-right-8 bg-background shadow-md hover:shadow-lg"
560
958
  * variant="ghost"
561
959
  * size="sm"
562
960
  * />
@@ -564,20 +962,47 @@ function CarouselPrevious({
564
962
  *
565
963
  * @example
566
964
  * ```tsx
567
- * // Vertical carousel positioning
568
- * <Carousel orientation="vertical">
965
+ * // Vertical carousel with rotated icons
966
+ * <Carousel orientation="vertical" className="h-[400px]">
569
967
  * <CarouselContent>...</CarouselContent>
570
- * <CarouselPrevious />
571
- * <CarouselNext />
968
+ * <CarouselPrevious className="-top-8" />
969
+ * <CarouselNext className="-bottom-8" />
572
970
  * </Carousel>
573
971
  * ```
574
972
  *
973
+ * @example
974
+ * ```tsx
975
+ * // Inside carousel bounds positioning
976
+ * <div className="relative">
977
+ * <Carousel>
978
+ * <CarouselContent>...</CarouselContent>
979
+ * <CarouselPrevious className="absolute left-4 top-1/2 -translate-y-1/2 z-10" />
980
+ * <CarouselNext className="absolute right-4 top-1/2 -translate-y-1/2 z-10" />
981
+ * </Carousel>
982
+ * </div>
983
+ * ```
984
+ *
985
+ * @example
986
+ * ```tsx
987
+ * // Custom button content and accessibility
988
+ * <CarouselNext
989
+ * variant="secondary"
990
+ * className="w-auto px-4"
991
+ * aria-label="Go to next product"
992
+ * >
993
+ * Next
994
+ * <ArrowRight className="w-4 h-4 ml-2" />
995
+ * </CarouselNext>
996
+ * ```
997
+ *
575
998
  * @accessibility
576
- * - Keyboard accessible with proper focus management
577
- * - Screen reader label "Next slide" for context
578
- * - Automatically disabled when cannot scroll further
579
- * - High contrast focus indicators
580
- * - Supports reduced motion preferences
999
+ * - **Keyboard Navigation**: Accessible via Tab and Enter/Space
1000
+ * - **Screen Reader**: Built-in "Next slide" label with sr-only text
1001
+ * - **Disabled State**: Automatically disabled when cannot scroll further
1002
+ * - **Focus Indicators**: High contrast focus ring for keyboard navigation
1003
+ * - **Motion**: Respects `prefers-reduced-motion` for animations
1004
+ * - **Touch**: Large enough touch target (44px minimum) for mobile accessibility
1005
+ * - **Icon**: ArrowRight icon rotated appropriately for vertical orientation
581
1006
  *
582
1007
  * @see {@link Carousel} Main carousel component
583
1008
  * @see {@link CarouselPrevious} Previous navigation button
@@ -589,7 +1014,7 @@ function CarouselNext({
589
1014
  variant = "outline",
590
1015
  size = "icon",
591
1016
  ...props
592
- }: React.ComponentProps<typeof Button>) {
1017
+ }: CarouselNextProps) {
593
1018
  const { orientation, scrollNext, canScrollNext } = useCarousel();
594
1019
 
595
1020
  return (
@@ -616,9 +1041,15 @@ function CarouselNext({
616
1041
 
617
1042
  export {
618
1043
  type CarouselApi,
1044
+ type CarouselProps,
1045
+ type CarouselContentProps,
1046
+ type CarouselItemProps,
1047
+ type CarouselPreviousProps,
1048
+ type CarouselNextProps,
619
1049
  Carousel,
620
1050
  CarouselContent,
621
1051
  CarouselItem,
622
1052
  CarouselPrevious,
623
1053
  CarouselNext,
1054
+ useCarousel,
624
1055
  };