@alquimia-ai/ui 1.2.1 → 1.2.4

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 (101) hide show
  1. package/dist/components/hooks/index.js +41 -32
  2. package/dist/components/hooks/index.js.map +1 -1
  3. package/dist/components/hooks/index.mjs +42 -33
  4. package/dist/components/hooks/index.mjs.map +1 -1
  5. package/dist/components/molecules/index.js +41 -32
  6. package/dist/components/molecules/index.js.map +1 -1
  7. package/dist/components/molecules/index.mjs +42 -33
  8. package/dist/components/molecules/index.mjs.map +1 -1
  9. package/dist/components/organisms/index.js +41 -32
  10. package/dist/components/organisms/index.js.map +1 -1
  11. package/dist/components/organisms/index.mjs +42 -33
  12. package/dist/components/organisms/index.mjs.map +1 -1
  13. package/dist/index.js +41 -32
  14. package/dist/index.js.map +1 -1
  15. package/dist/index.mjs +42 -33
  16. package/dist/index.mjs.map +1 -1
  17. package/dist/package.json +136 -0
  18. package/package.json +50 -53
  19. package/src/components/atoms/index.ts +0 -32
  20. package/src/components/atoms/ui/alert.tsx +0 -59
  21. package/src/components/atoms/ui/aspect-ratio.tsx +0 -7
  22. package/src/components/atoms/ui/avatar.tsx +0 -50
  23. package/src/components/atoms/ui/badge.tsx +0 -36
  24. package/src/components/atoms/ui/breadcrumb.tsx +0 -120
  25. package/src/components/atoms/ui/button.tsx +0 -56
  26. package/src/components/atoms/ui/card.tsx +0 -87
  27. package/src/components/atoms/ui/checkbox.tsx +0 -31
  28. package/src/components/atoms/ui/command.tsx +0 -155
  29. package/src/components/atoms/ui/dialog.tsx +0 -125
  30. package/src/components/atoms/ui/drawer.tsx +0 -119
  31. package/src/components/atoms/ui/input.tsx +0 -26
  32. package/src/components/atoms/ui/label.tsx +0 -26
  33. package/src/components/atoms/ui/loader.tsx +0 -52
  34. package/src/components/atoms/ui/popover.tsx +0 -31
  35. package/src/components/atoms/ui/rich-text.tsx +0 -19
  36. package/src/components/atoms/ui/scroll-area.tsx +0 -48
  37. package/src/components/atoms/ui/select.tsx +0 -160
  38. package/src/components/atoms/ui/skeleton.tsx +0 -15
  39. package/src/components/atoms/ui/slider.tsx +0 -29
  40. package/src/components/atoms/ui/switch.tsx +0 -30
  41. package/src/components/atoms/ui/table.tsx +0 -118
  42. package/src/components/atoms/ui/tabs.tsx +0 -56
  43. package/src/components/atoms/ui/text-area/index.tsx +0 -24
  44. package/src/components/atoms/ui/textarea.tsx +0 -25
  45. package/src/components/atoms/ui/think-indicator.tsx +0 -103
  46. package/src/components/atoms/ui/toast.tsx +0 -129
  47. package/src/components/atoms/ui/toaster.tsx +0 -38
  48. package/src/components/atoms/ui/toggle.tsx +0 -45
  49. package/src/components/atoms/ui/typography/index.tsx +0 -30
  50. package/src/components/hooks/index.ts +0 -4
  51. package/src/components/hooks/use-document.tsx +0 -44
  52. package/src/components/hooks/use-resize-observer.ts +0 -28
  53. package/src/components/hooks/use-text-streaming.ts +0 -63
  54. package/src/components/hooks/use-toast.ts +0 -194
  55. package/src/components/index.ts +0 -1
  56. package/src/components/molecules/alert-dialog.tsx +0 -141
  57. package/src/components/molecules/assistant-button.tsx +0 -148
  58. package/src/components/molecules/call-out.tsx +0 -163
  59. package/src/components/molecules/carousel.tsx +0 -262
  60. package/src/components/molecules/documents/document-selector.tsx +0 -79
  61. package/src/components/molecules/documents/document-viewer.tsx +0 -85
  62. package/src/components/molecules/documents/index.ts +0 -2
  63. package/src/components/molecules/index.ts +0 -11
  64. package/src/components/molecules/navigation-menu.tsx +0 -128
  65. package/src/components/molecules/page-container.tsx +0 -17
  66. package/src/components/molecules/rating-comment.tsx +0 -93
  67. package/src/components/molecules/rating-stars.tsx +0 -136
  68. package/src/components/molecules/rating-thumbs.tsx +0 -90
  69. package/src/components/molecules/sidebar.tsx +0 -107
  70. package/src/components/molecules/sonner.tsx +0 -30
  71. package/src/components/molecules/viewers/index.ts +0 -2
  72. package/src/components/molecules/viewers/pdf-viewer.tsx +0 -138
  73. package/src/components/molecules/viewers/plain-text-viewer.tsx +0 -40
  74. package/src/components/organisms/assistant.tsx +0 -271
  75. package/src/components/organisms/index.ts +0 -6
  76. package/src/components/organisms/rating-dialog.tsx +0 -104
  77. package/src/components/organisms/speechToText.tsx +0 -92
  78. package/src/components/organisms/whisper.tsx +0 -106
  79. package/src/components/templates/cards/index.ts +0 -2
  80. package/src/components/templates/cards/with-image-heading-description-avatar.tsx +0 -94
  81. package/src/components/templates/cards/with-image-heading-description.tsx +0 -63
  82. package/src/components/templates/hero/index.tsx +0 -39
  83. package/src/components/templates/index.ts +0 -4
  84. package/src/components/templates/messages-window.tsx +0 -15
  85. package/src/components/templates/query-box.tsx +0 -13
  86. package/src/components/ui/input.tsx +0 -25
  87. package/src/components/ui/select.tsx +0 -163
  88. package/src/index.ts +0 -7
  89. package/src/lib/index.ts +0 -1
  90. package/src/lib/utils.ts +0 -34
  91. package/src/styles/call-out.css +0 -153
  92. package/src/styles/drawer.css +0 -28
  93. package/src/styles/globals.css +0 -69
  94. package/src/styles/prose.css +0 -51
  95. package/src/styles/ratings.css +0 -27
  96. package/src/styles/themes/base-alquimia.css +0 -95
  97. package/src/styles/themes/base-nordic.css +0 -83
  98. package/src/styles/themes/base-primary.css +0 -85
  99. package/src/styles/themes/base.css +0 -8
  100. package/src/types/index.ts +0 -1
  101. package/src/types/type.ts +0 -76
@@ -1,141 +0,0 @@
1
- "use client";
2
-
3
- import * as React from "react";
4
- import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog";
5
-
6
- import { cn } from "../../lib/utils";
7
- import { buttonVariants } from "../atoms/ui/button";
8
-
9
- const AlertDialog = AlertDialogPrimitive.Root;
10
-
11
- const AlertDialogTrigger = AlertDialogPrimitive.Trigger;
12
-
13
- const AlertDialogPortal = AlertDialogPrimitive.Portal;
14
-
15
- const AlertDialogOverlay = React.forwardRef<
16
- React.ElementRef<typeof AlertDialogPrimitive.Overlay>,
17
- React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Overlay>
18
- >(({ className, ...props }, ref) => (
19
- <AlertDialogPrimitive.Overlay
20
- className={cn(
21
- "fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
22
- className
23
- )}
24
- {...props}
25
- ref={ref}
26
- />
27
- ));
28
- AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName;
29
-
30
- const AlertDialogContent = React.forwardRef<
31
- React.ElementRef<typeof AlertDialogPrimitive.Content>,
32
- React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Content>
33
- >(({ className, ...props }, ref) => (
34
- <AlertDialogPortal>
35
- <AlertDialogOverlay />
36
- <AlertDialogPrimitive.Content
37
- ref={ref}
38
- className={cn(
39
- "fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
40
- className
41
- )}
42
- {...props}
43
- />
44
- </AlertDialogPortal>
45
- ));
46
- AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName;
47
-
48
- const AlertDialogHeader = ({
49
- className,
50
- ...props
51
- }: React.HTMLAttributes<HTMLDivElement>) => (
52
- <div
53
- className={cn(
54
- "flex flex-col space-y-2 text-center sm:text-left",
55
- className
56
- )}
57
- {...props}
58
- />
59
- );
60
- AlertDialogHeader.displayName = "AlertDialogHeader";
61
-
62
- const AlertDialogFooter = ({
63
- className,
64
- ...props
65
- }: React.HTMLAttributes<HTMLDivElement>) => (
66
- <div
67
- className={cn(
68
- "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
69
- className
70
- )}
71
- {...props}
72
- />
73
- );
74
- AlertDialogFooter.displayName = "AlertDialogFooter";
75
-
76
- const AlertDialogTitle = React.forwardRef<
77
- React.ElementRef<typeof AlertDialogPrimitive.Title>,
78
- React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Title>
79
- >(({ className, ...props }, ref) => (
80
- <AlertDialogPrimitive.Title
81
- ref={ref}
82
- className={cn("text-lg font-semibold", className)}
83
- {...props}
84
- />
85
- ));
86
- AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName;
87
-
88
- const AlertDialogDescription = React.forwardRef<
89
- React.ElementRef<typeof AlertDialogPrimitive.Description>,
90
- React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Description>
91
- >(({ className, ...props }, ref) => (
92
- <AlertDialogPrimitive.Description
93
- ref={ref}
94
- className={cn("text-sm text-muted-foreground", className)}
95
- {...props}
96
- />
97
- ));
98
- AlertDialogDescription.displayName =
99
- AlertDialogPrimitive.Description.displayName;
100
-
101
- const AlertDialogAction = React.forwardRef<
102
- React.ElementRef<typeof AlertDialogPrimitive.Action>,
103
- React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Action>
104
- >(({ className, ...props }, ref) => (
105
- <AlertDialogPrimitive.Action
106
- ref={ref}
107
- className={cn(buttonVariants(), className)}
108
- {...props}
109
- />
110
- ));
111
- AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName;
112
-
113
- const AlertDialogCancel = React.forwardRef<
114
- React.ElementRef<typeof AlertDialogPrimitive.Cancel>,
115
- React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Cancel>
116
- >(({ className, ...props }, ref) => (
117
- <AlertDialogPrimitive.Cancel
118
- ref={ref}
119
- className={cn(
120
- buttonVariants({ variant: "outline" }),
121
- "mt-2 sm:mt-0",
122
- className
123
- )}
124
- {...props}
125
- />
126
- ));
127
- AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName;
128
-
129
- export {
130
- AlertDialog,
131
- AlertDialogPortal,
132
- AlertDialogOverlay,
133
- AlertDialogTrigger,
134
- AlertDialogContent,
135
- AlertDialogHeader,
136
- AlertDialogFooter,
137
- AlertDialogTitle,
138
- AlertDialogDescription,
139
- AlertDialogAction,
140
- AlertDialogCancel,
141
- };
@@ -1,148 +0,0 @@
1
- "use client";
2
-
3
- import * as React from "react";
4
- import { useState, useEffect } from "react";
5
- import { LucideIcon } from "lucide-react";
6
- import { Button } from "../atoms";
7
- import { cn } from "../../lib/utils";
8
-
9
- interface Suggestion {
10
- label: string;
11
- icon: LucideIcon;
12
- action: () => void;
13
- }
14
-
15
- interface AssistantSuggestionsProps {
16
- suggestions: Suggestion[];
17
- className?: string;
18
- showSuggestions: boolean;
19
- }
20
-
21
- const AssistantSuggestions = React.forwardRef<
22
- HTMLDivElement,
23
- AssistantSuggestionsProps
24
- >(({ suggestions, showSuggestions, className }, ref) => {
25
- return (
26
- <div
27
- ref={ref}
28
- className={cn(
29
- "absolute bottom-[calc(100%+0.5rem)] right-0 pb-2 mb-4 alq--assistant-suggestions-container",
30
- "transition-all duration-300",
31
- showSuggestions
32
- ? "opacity-100 translate-y-0"
33
- : "opacity-0 translate-y-4",
34
- className
35
- )}
36
- >
37
- <div className="rounded-lg p-2 pr-0 w-64">
38
- {suggestions.map((suggestion, index) => (
39
- <button
40
- key={index}
41
- onClick={() => suggestion.action?.()}
42
- style={{
43
- transitionDelay: showSuggestions ? `${index * 50}ms` : "0ms",
44
- }}
45
- className={cn(
46
- "bg-background flex items-center gap-2 border p-2 pr-4 my-2 rounded-full ml-auto",
47
- "text-primary hover:bg-secondary",
48
- "transition-all duration-100",
49
- "origin-bottom w-fit",
50
- "alq--assistant-suggestion",
51
- showSuggestions
52
- ? "opacity-100 translate-y-0"
53
- : "opacity-0 translate-y-4"
54
- )}
55
- >
56
- <suggestion.icon className="w-5 h-5 text-primary" />
57
- <span className="text-xs whitespace-nowrap font-normal">
58
- {suggestion.label}
59
- </span>
60
- </button>
61
- ))}
62
- </div>
63
- </div>
64
- );
65
- });
66
-
67
- AssistantSuggestions.displayName = "Suggestions";
68
-
69
- interface AssistantButtonProps {
70
- icon: LucideIcon;
71
- clickAction: () => void;
72
- className?: string;
73
- suggestions?: Suggestion[];
74
- }
75
-
76
- export const AssistantButton = React.forwardRef<
77
- HTMLDivElement,
78
- AssistantButtonProps
79
- >(
80
- (
81
- {
82
- icon: Icon,
83
- clickAction,
84
- className,
85
- suggestions = [],
86
- },
87
- ref
88
- ) => {
89
- const [isVisible, setIsVisible] = useState(false);
90
- const [showSuggestions, setShowSuggestions] = useState(false);
91
-
92
- const handleMouseEnter = () => {
93
- setIsVisible(true);
94
- requestAnimationFrame(() => {
95
- requestAnimationFrame(() => {
96
- setShowSuggestions(true);
97
- });
98
- });
99
- };
100
-
101
- const handleMouseLeave = () => {
102
- setShowSuggestions(false);
103
- setTimeout(() => setIsVisible(false), 300);
104
- };
105
-
106
- return (
107
- <div
108
- ref={ref}
109
- className={cn(
110
- "fixed bottom-8 right-4 z-50",
111
- "alq--assistant-button-container",
112
- className
113
- )}
114
- onMouseEnter={handleMouseEnter}
115
- onMouseLeave={handleMouseLeave}
116
- >
117
- <div className="relative group">
118
- {isVisible && suggestions.length > 0 && (
119
- <AssistantSuggestions
120
- suggestions={suggestions}
121
- showSuggestions={showSuggestions}
122
- />
123
- )}
124
- <Button
125
- variant="outline"
126
- size="sm"
127
- className={cn(
128
- "fixed hover:bg-opacity-70 transition-all duration-300",
129
- "bottom-4 h-12 w-12 right-4 z-50 rounded-full p-2",
130
- "shadow-md",
131
- "hover:shadow-lg",
132
- showSuggestions ? "scale-110" : "hover:scale-105",
133
- "alq--assistant-button"
134
- )}
135
- onClick={clickAction}
136
- >
137
- <Icon
138
- style={{ width: "22px", height: "22px" }}
139
- className="text-primary"
140
- />
141
- </Button>
142
- </div>
143
- </div>
144
- );
145
- }
146
- );
147
-
148
- AssistantButton.displayName = "AssistantButton";
@@ -1,163 +0,0 @@
1
- import * as React from "react";
2
-
3
- import { cn } from "../../lib/utils";
4
- import { RichText } from "../atoms";
5
- import { Message } from "ai";
6
- import { useTextStreaming } from "../hooks/use-text-streaming";
7
-
8
- export interface CallOutMessage {
9
- id: string;
10
- role: "user" | "assistant";
11
- content: string;
12
- timestamp: Date;
13
- }
14
-
15
- interface CallOutActionProps {
16
- label: string;
17
- icon: React.ReactNode;
18
- onClick: (message?: Message) => Promise<void>;
19
- }
20
-
21
- export interface CallOutProps extends React.HTMLAttributes<HTMLDivElement> {
22
- message?: Message;
23
- }
24
-
25
- const CallOut = React.forwardRef<
26
- HTMLDivElement,
27
- React.HTMLAttributes<HTMLDivElement> & CallOutProps
28
- >(({ className, children, role, ...props }, ref) => {
29
- return (
30
- <div
31
- ref={ref}
32
- className={cn("alq--callout-box", className)}
33
- data-role={role}
34
- {...props}
35
- >
36
- {children}
37
- </div>
38
- );
39
- });
40
-
41
- const CallOutDate = React.forwardRef<
42
- HTMLDivElement,
43
- React.HTMLAttributes<HTMLDivElement>
44
- >(({ className, children, ...props }, ref) => {
45
- return (
46
- <div
47
- ref={ref}
48
- className={cn(
49
- "alq--callout-date",
50
- "text-sm text-muted-foreground",
51
- className
52
- )}
53
- {...props}
54
- >
55
- {children}
56
- </div>
57
- );
58
- });
59
-
60
- const CallOutActions = React.forwardRef<
61
- HTMLDivElement,
62
- React.HTMLAttributes<HTMLDivElement> & {
63
- actions: CallOutActionProps[];
64
- role: "user" | "assistant";
65
- message?: Message;
66
- }
67
- >(({ className, actions, role, message, ...props }, ref) => {
68
- const [isLoading, setIsLoading] = React.useState(false);
69
- const [isClicked, setIsClicked] = React.useState(false);
70
-
71
- if (role === "user") {
72
- return null;
73
- }
74
-
75
- return (
76
- <div ref={ref} className={cn("alq--callout-actions", className)} {...props}>
77
- {actions.map((action) => (
78
- <button
79
- key={action.label}
80
- className={cn(
81
- "alq--callout-action",
82
- {
83
- "alq--callout-animate-action": isLoading,
84
- },
85
- {
86
- "alq--callout-clicked-action": isClicked,
87
- }
88
- )}
89
- type="button"
90
- title={action.label}
91
- onClick={() => {
92
- setIsLoading(true);
93
- action.onClick(message).then(() => {
94
- setIsLoading(false);
95
- setIsClicked(true);
96
- });
97
- }}
98
- >
99
- <span
100
- className={cn("alq-action-icon-wrapper", {
101
- "alq--callout-animate-action": isLoading,
102
- })}
103
- >
104
- {action.icon}
105
- </span>
106
- <label>{action.label}</label>
107
- </button>
108
- ))}
109
- </div>
110
- );
111
- });
112
-
113
- const CallOutResponse = React.forwardRef<
114
- HTMLDivElement,
115
- React.HTMLAttributes<HTMLDivElement> & {
116
- role: Message["role"];
117
- additionalInfo?: string;
118
- isStreaming?: boolean;
119
- handleIsTextStreaming?: (isStreaming: boolean) => void;
120
- }
121
- >(
122
- (
123
- { className, children, role, additionalInfo, isStreaming, handleIsTextStreaming, ...props },
124
- ref
125
- ) => {
126
- const content = String(children || "");
127
- const shouldStream = role === "assistant" && isStreaming;
128
- const displayedContent = useTextStreaming(content, shouldStream ?? false, handleIsTextStreaming);
129
-
130
- return (
131
- <div
132
- ref={ref}
133
- data-role={role}
134
- className={cn(
135
- "alq--callout-response",
136
- "max-w-none",
137
- "text-foreground",
138
- className
139
- )}
140
- {...props}
141
- >
142
- <RichText content={displayedContent} />
143
- {additionalInfo && (
144
- <div
145
- className={cn(
146
- "alq--callout-response-additional-info",
147
- "mt-2 text-sm text-muted-foreground",
148
- "border-t border-border pt-2"
149
- )}
150
- >
151
- {additionalInfo}
152
- </div>
153
- )}
154
- </div>
155
- );
156
- }
157
- );
158
-
159
- CallOut.displayName = "CallOut";
160
- CallOutDate.displayName = "CallOutDate";
161
- CallOutActions.displayName = "CallOutActions";
162
- CallOutResponse.displayName = "CallOutResponse";
163
- export { CallOut, CallOutDate, CallOutResponse, CallOutActions };
@@ -1,262 +0,0 @@
1
- "use client";
2
-
3
- import * as React from "react";
4
- import useEmblaCarousel, {
5
- type UseEmblaCarouselType,
6
- } from "embla-carousel-react";
7
- import { ArrowLeft, ArrowRight } from "lucide-react";
8
-
9
- import { cn } from "../../lib/utils";
10
- import { Button } from "../../components/atoms/ui/button";
11
-
12
- type CarouselApi = UseEmblaCarouselType[1];
13
- type UseCarouselParameters = Parameters<typeof useEmblaCarousel>;
14
- type CarouselOptions = UseCarouselParameters[0];
15
- type CarouselPlugin = UseCarouselParameters[1];
16
-
17
- type CarouselProps = {
18
- opts?: CarouselOptions;
19
- plugins?: CarouselPlugin;
20
- orientation?: "horizontal" | "vertical";
21
- setApi?: (api: CarouselApi) => void;
22
- };
23
-
24
- type CarouselContextProps = {
25
- carouselRef: ReturnType<typeof useEmblaCarousel>[0];
26
- api: ReturnType<typeof useEmblaCarousel>[1];
27
- scrollPrev: () => void;
28
- scrollNext: () => void;
29
- canScrollPrev: boolean;
30
- canScrollNext: boolean;
31
- } & CarouselProps;
32
-
33
- const CarouselContext = React.createContext<CarouselContextProps | null>(null);
34
-
35
- function useCarousel() {
36
- const context = React.useContext(CarouselContext);
37
-
38
- if (!context) {
39
- throw new Error("useCarousel must be used within a <Carousel />");
40
- }
41
-
42
- return context;
43
- }
44
-
45
- const Carousel = React.forwardRef<
46
- HTMLDivElement,
47
- React.HTMLAttributes<HTMLDivElement> & CarouselProps
48
- >(
49
- (
50
- {
51
- orientation = "horizontal",
52
- opts,
53
- setApi,
54
- plugins,
55
- className,
56
- children,
57
- ...props
58
- },
59
- ref
60
- ) => {
61
- const [carouselRef, api] = useEmblaCarousel(
62
- {
63
- ...opts,
64
- axis: orientation === "horizontal" ? "x" : "y",
65
- },
66
- plugins
67
- );
68
- const [canScrollPrev, setCanScrollPrev] = React.useState(false);
69
- const [canScrollNext, setCanScrollNext] = React.useState(false);
70
-
71
- const onSelect = React.useCallback((api: CarouselApi) => {
72
- if (!api) {
73
- return;
74
- }
75
-
76
- setCanScrollPrev(api.canScrollPrev());
77
- setCanScrollNext(api.canScrollNext());
78
- }, []);
79
-
80
- const scrollPrev = React.useCallback(() => {
81
- api?.scrollPrev();
82
- }, [api]);
83
-
84
- const scrollNext = React.useCallback(() => {
85
- api?.scrollNext();
86
- }, [api]);
87
-
88
- const handleKeyDown = React.useCallback(
89
- (event: React.KeyboardEvent<HTMLDivElement>) => {
90
- if (event.key === "ArrowLeft") {
91
- event.preventDefault();
92
- scrollPrev();
93
- } else if (event.key === "ArrowRight") {
94
- event.preventDefault();
95
- scrollNext();
96
- }
97
- },
98
- [scrollPrev, scrollNext]
99
- );
100
-
101
- React.useEffect(() => {
102
- if (!api || !setApi) {
103
- return;
104
- }
105
-
106
- setApi(api);
107
- }, [api, setApi]);
108
-
109
- React.useEffect(() => {
110
- if (!api) {
111
- return;
112
- }
113
-
114
- onSelect(api);
115
- api.on("reInit", onSelect);
116
- api.on("select", onSelect);
117
-
118
- return () => {
119
- api?.off("select", onSelect);
120
- };
121
- }, [api, onSelect]);
122
-
123
- return (
124
- <CarouselContext.Provider
125
- value={{
126
- carouselRef,
127
- api: api,
128
- opts,
129
- orientation:
130
- orientation || (opts?.axis === "y" ? "vertical" : "horizontal"),
131
- scrollPrev,
132
- scrollNext,
133
- canScrollPrev,
134
- canScrollNext,
135
- }}
136
- >
137
- <div
138
- ref={ref}
139
- onKeyDownCapture={handleKeyDown}
140
- className={cn("relative", className)}
141
- role="region"
142
- aria-roledescription="carousel"
143
- {...props}
144
- >
145
- {children}
146
- </div>
147
- </CarouselContext.Provider>
148
- );
149
- }
150
- );
151
- Carousel.displayName = "Carousel";
152
-
153
- const CarouselContent = React.forwardRef<
154
- HTMLDivElement,
155
- React.HTMLAttributes<HTMLDivElement>
156
- >(({ className, ...props }, ref) => {
157
- const { carouselRef, orientation } = useCarousel();
158
-
159
- return (
160
- <div ref={carouselRef} className="overflow-hidden">
161
- <div
162
- ref={ref}
163
- className={cn(
164
- "flex",
165
- orientation === "horizontal" ? "-ml-4" : "-mt-4 flex-col",
166
- className
167
- )}
168
- {...props}
169
- />
170
- </div>
171
- );
172
- });
173
- CarouselContent.displayName = "CarouselContent";
174
-
175
- const CarouselItem = React.forwardRef<
176
- HTMLDivElement,
177
- React.HTMLAttributes<HTMLDivElement>
178
- >(({ className, ...props }, ref) => {
179
- const { orientation } = useCarousel();
180
-
181
- return (
182
- <div
183
- ref={ref}
184
- role="group"
185
- aria-roledescription="slide"
186
- className={cn(
187
- "min-w-0 shrink-0 grow-0 basis-full",
188
- orientation === "horizontal" ? "pl-4" : "pt-4",
189
- className
190
- )}
191
- {...props}
192
- />
193
- );
194
- });
195
- CarouselItem.displayName = "CarouselItem";
196
-
197
- const CarouselPrevious = React.forwardRef<
198
- HTMLButtonElement,
199
- React.ComponentProps<typeof Button>
200
- >(({ className, variant = "outline", size = "icon", ...props }, ref) => {
201
- const { orientation, scrollPrev, canScrollPrev } = useCarousel();
202
-
203
- return (
204
- <Button
205
- ref={ref}
206
- variant={variant}
207
- size={size}
208
- className={cn(
209
- "absolute h-8 w-8 rounded-full",
210
- orientation === "horizontal"
211
- ? "-left-12 top-1/2 -translate-y-1/2"
212
- : "-top-12 left-1/2 -translate-x-1/2 rotate-90",
213
- className
214
- )}
215
- disabled={!canScrollPrev}
216
- onClick={scrollPrev}
217
- {...props}
218
- >
219
- <ArrowLeft className="h-4 w-4" />
220
- <span className="sr-only">Previous slide</span>
221
- </Button>
222
- );
223
- });
224
- CarouselPrevious.displayName = "CarouselPrevious";
225
-
226
- const CarouselNext = React.forwardRef<
227
- HTMLButtonElement,
228
- React.ComponentProps<typeof Button>
229
- >(({ className, variant = "outline", size = "icon", ...props }, ref) => {
230
- const { orientation, scrollNext, canScrollNext } = useCarousel();
231
-
232
- return (
233
- <Button
234
- ref={ref}
235
- variant={variant}
236
- size={size}
237
- className={cn(
238
- "absolute h-8 w-8 rounded-full",
239
- orientation === "horizontal"
240
- ? "-right-12 top-1/2 -translate-y-1/2"
241
- : "-bottom-12 left-1/2 -translate-x-1/2 rotate-90",
242
- className
243
- )}
244
- disabled={!canScrollNext}
245
- onClick={scrollNext}
246
- {...props}
247
- >
248
- <ArrowRight className="h-4 w-4" />
249
- <span className="sr-only">Next slide</span>
250
- </Button>
251
- );
252
- });
253
- CarouselNext.displayName = "CarouselNext";
254
-
255
- export {
256
- type CarouselApi,
257
- Carousel,
258
- CarouselContent,
259
- CarouselItem,
260
- CarouselPrevious,
261
- CarouselNext,
262
- };