@syscore/ui-library 1.1.9 → 1.1.10

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 (45) hide show
  1. package/client/components/ui/Navigation.tsx +958 -0
  2. package/client/components/ui/SearchField.tsx +157 -0
  3. package/client/components/ui/StrategyTable.tsx +303 -0
  4. package/client/components/ui/Tag.tsx +127 -0
  5. package/client/components/ui/alert-dialog.tsx +1 -1
  6. package/client/components/ui/button.tsx +67 -127
  7. package/client/components/ui/calendar.tsx +2 -2
  8. package/client/components/ui/card.tsx +10 -13
  9. package/client/components/ui/carousel.tsx +56 -46
  10. package/client/components/ui/command.tsx +27 -16
  11. package/client/components/ui/dialog.tsx +113 -92
  12. package/client/components/ui/label.tsx +5 -3
  13. package/client/components/ui/menubar.tsx +1 -1
  14. package/client/components/ui/pagination.tsx +3 -3
  15. package/client/components/ui/sidebar.tsx +1 -1
  16. package/client/components/ui/tabs.tsx +350 -5
  17. package/client/components/ui/toggle.tsx +71 -19
  18. package/client/components/ui/tooltip.tsx +69 -18
  19. package/client/global.css +635 -58
  20. package/dist/ui/fonts/FT-Made/FTMade-Regular.otf +0 -0
  21. package/dist/ui/fonts/FT-Made/FTMade-Regular.ttf +0 -0
  22. package/dist/ui/fonts/FT-Made/FTMade-Regular.woff +0 -0
  23. package/dist/ui/fonts/FT-Made/FTMade-Regular.woff2 +0 -0
  24. package/dist/ui/fonts/Mazzard-M/mazzardsoftm-black.otf +0 -0
  25. package/dist/ui/fonts/Mazzard-M/mazzardsoftm-blackitalic.otf +0 -0
  26. package/dist/ui/fonts/Mazzard-M/mazzardsoftm-bold.otf +0 -0
  27. package/dist/ui/fonts/Mazzard-M/mazzardsoftm-bolditalic.otf +0 -0
  28. package/dist/ui/fonts/Mazzard-M/mazzardsoftm-extrabold.otf +0 -0
  29. package/dist/ui/fonts/Mazzard-M/mazzardsoftm-extrabolditalic.otf +0 -0
  30. package/dist/ui/fonts/Mazzard-M/mazzardsoftm-extralight.otf +0 -0
  31. package/dist/ui/fonts/Mazzard-M/mazzardsoftm-extralightitalic.otf +0 -0
  32. package/dist/ui/fonts/Mazzard-M/mazzardsoftm-italic.otf +0 -0
  33. package/dist/ui/fonts/Mazzard-M/mazzardsoftm-light.otf +0 -0
  34. package/dist/ui/fonts/Mazzard-M/mazzardsoftm-lightitalic.otf +0 -0
  35. package/dist/ui/fonts/Mazzard-M/mazzardsoftm-medium.otf +0 -0
  36. package/dist/ui/fonts/Mazzard-M/mazzardsoftm-mediumitalic.otf +0 -0
  37. package/dist/ui/fonts/Mazzard-M/mazzardsoftm-regular.otf +0 -0
  38. package/dist/ui/fonts/Mazzard-M/mazzardsoftm-semibold.otf +0 -0
  39. package/dist/ui/fonts/Mazzard-M/mazzardsoftm-semibolditalic.otf +0 -0
  40. package/dist/ui/fonts/Mazzard-M/mazzardsoftm-thin.otf +0 -0
  41. package/dist/ui/fonts/Mazzard-M/mazzardsoftm-thinitalic.otf +0 -0
  42. package/dist/ui/index.cjs.js +1 -1
  43. package/dist/ui/index.d.ts +1 -1
  44. package/dist/ui/index.es.js +401 -329
  45. package/package.json +3 -2
@@ -1,9 +1,353 @@
1
- import * as React from "react";
1
+ "use client";
2
+
3
+ import React from "react";
4
+
5
+ import { AnimatePresence, motion } from "motion/react";
2
6
  import * as TabsPrimitive from "@radix-ui/react-tabs";
3
7
 
8
+ import { useTabs, type Tab } from "../../hooks/UseTabs";
4
9
  import { cn } from "@/lib/utils";
5
10
 
6
- const Tabs = TabsPrimitive.Root;
11
+ interface AnimatedTabsProps {
12
+ tabs: Tab[];
13
+ }
14
+
15
+ const transition = {
16
+ type: "tween" as const,
17
+ ease: "easeOut" as const,
18
+ duration: 0.15,
19
+ };
20
+
21
+ const getHoverAnimationProps = (hoveredRect: DOMRect, navRect: DOMRect) => ({
22
+ x: hoveredRect.left - navRect.left - 10,
23
+ y: hoveredRect.top - navRect.top - 4,
24
+ width: hoveredRect.width + 20,
25
+ height: hoveredRect.height + 10,
26
+ });
27
+
28
+ const TabContent = ({ tab }: { tab: Tab }) => {
29
+ return (
30
+ <motion.div
31
+ initial={{ opacity: 0, y: 10 }}
32
+ animate={{ opacity: 1, y: 0 }}
33
+ exit={{ opacity: 0, y: -10 }}
34
+ transition={transition}
35
+ className="p-6 bg-zinc-50 dark:bg-zinc-900 rounded-lg mt-4 h-[55vh]"
36
+ >
37
+ {tab.value === "home" && (
38
+ <div className="space-y-6">
39
+ <div className="border-b pb-6 dark:border-zinc-800">
40
+ <h2 className="text-3xl font-bold mb-4">Welcome to Our Platform</h2>
41
+ <p className="text-zinc-600 dark:text-zinc-400 mb-4">
42
+ Discover a new way to manage your projects and collaborate with
43
+ your team.
44
+ </p>
45
+ <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
46
+ <div className="p-4 bg-white dark:bg-zinc-800 rounded-lg">
47
+ <h3 className="font-semibold mb-2">Quick Start</h3>
48
+ <p className="text-sm text-zinc-600 dark:text-zinc-400">
49
+ Get started with our platform in minutes
50
+ </p>
51
+ </div>
52
+ <div className="p-4 bg-white dark:bg-zinc-800 rounded-lg">
53
+ <h3 className="font-semibold mb-2">Latest Updates</h3>
54
+ <p className="text-sm text-zinc-600 dark:text-zinc-400">
55
+ See what&apos;s new in our latest release
56
+ </p>
57
+ </div>
58
+ <div className="p-4 bg-white dark:bg-zinc-800 rounded-lg">
59
+ <h3 className="font-semibold mb-2">Resources</h3>
60
+ <p className="text-sm text-zinc-600 dark:text-zinc-400">
61
+ Access guides and documentation
62
+ </p>
63
+ </div>
64
+ </div>
65
+ </div>
66
+ <div>
67
+ <h3 className="text-xl font-semibold mb-4">Recent Activity</h3>
68
+ <div className="space-y-3">
69
+ <div className="flex items-center gap-3 p-3 bg-white dark:bg-zinc-800 rounded-lg">
70
+ <div className="w-2 h-2 bg-green-500 rounded-full"></div>
71
+ <p className="text-sm">
72
+ Project &quot;Marketing Campaign&quot; was updated 2 hours ago
73
+ </p>
74
+ </div>
75
+ <div className="flex items-center gap-3 p-3 bg-white dark:bg-zinc-800 rounded-lg">
76
+ <div className="w-2 h-2 bg-blue-500 rounded-full"></div>
77
+ <p className="text-sm">
78
+ New team member John Doe joined the platform
79
+ </p>
80
+ </div>
81
+ </div>
82
+ </div>
83
+ </div>
84
+ )}
85
+ {tab.value === "about" && (
86
+ <div className="space-y-8">
87
+ <div>
88
+ <h2 className="text-3xl font-bold mb-4">About Us</h2>
89
+ <p className="text-zinc-600 dark:text-zinc-400 mb-6">
90
+ We&apos;re a team of passionate individuals working together to
91
+ create amazing solutions for our clients.
92
+ </p>
93
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
94
+ <div>
95
+ <h3 className="text-xl font-semibold mb-3">Our Mission</h3>
96
+ <p className="text-zinc-600 dark:text-zinc-400">
97
+ To empower businesses with innovative tools and solutions that
98
+ drive growth and success in the digital age.
99
+ </p>
100
+ </div>
101
+ <div>
102
+ <h3 className="text-xl font-semibold mb-3">Our Vision</h3>
103
+ <p className="text-zinc-600 dark:text-zinc-400">
104
+ To become the leading platform for business transformation and
105
+ digital innovation worldwide.
106
+ </p>
107
+ </div>
108
+ </div>
109
+ </div>
110
+ </div>
111
+ )}
112
+ {tab.value === "contact" && (
113
+ <div className="max-w-2xl mx-auto">
114
+ <h2 className="text-3xl font-bold mb-6">Get in Touch</h2>
115
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-8 mb-8">
116
+ <div>
117
+ <h3 className="text-xl font-semibold mb-4">
118
+ Contact Information
119
+ </h3>
120
+ <div className="space-y-4">
121
+ <div>
122
+ <p className="font-medium">Address</p>
123
+ <p className="text-zinc-600 dark:text-zinc-400">
124
+ 123 Business Street
125
+ </p>
126
+ <p className="text-zinc-600 dark:text-zinc-400">
127
+ San Francisco, CA 94105
128
+ </p>
129
+ </div>
130
+ <div>
131
+ <p className="font-medium">Email</p>
132
+ <p className="text-zinc-600 dark:text-zinc-400">
133
+ contact@example.com
134
+ </p>
135
+ </div>
136
+ <div>
137
+ <p className="font-medium">Phone</p>
138
+ <p className="text-zinc-600 dark:text-zinc-400">
139
+ +1 (555) 123-4567
140
+ </p>
141
+ </div>
142
+ </div>
143
+ </div>
144
+ <div className="space-y-4">
145
+ <div>
146
+ <label className="block text-sm font-medium mb-1">Name</label>
147
+ <input
148
+ type="text"
149
+ className="w-full p-2 rounded-md border dark:bg-zinc-800 dark:border-zinc-700"
150
+ />
151
+ </div>
152
+ <div>
153
+ <label className="block text-sm font-medium mb-1">Email</label>
154
+ <input
155
+ type="email"
156
+ className="w-full p-2 rounded-md border dark:bg-zinc-800 dark:border-zinc-700"
157
+ />
158
+ </div>
159
+ <button className="w-full bg-black text-white dark:bg-white dark:text-black py-2 rounded-md font-medium">
160
+ Send Message
161
+ </button>
162
+ </div>
163
+ </div>
164
+ </div>
165
+ )}
166
+ {tab.value === "danger-zone" && (
167
+ <div className="max-w-2xl mx-auto">
168
+ <h2 className="text-2xl font-bold mb-6 text-red-500">Caution!</h2>
169
+ <div className="space-y-6">
170
+ <div className="border border-red-200 dark:border-red-900 rounded-lg p-6 bg-red-50 dark:bg-red-900/20">
171
+ <h3 className="text-lg font-semibold text-red-600 dark:text-red-400 mb-2">
172
+ Delete Account
173
+ </h3>
174
+ <p className="text-red-600/80 dark:text-red-400/80 mb-4">
175
+ This action cannot be undone. This will permanently delete your
176
+ account and remove your data from our servers.
177
+ </p>
178
+ <div className="flex items-center gap-4">
179
+ <input
180
+ type="text"
181
+ placeholder="Type 'delete' to confirm"
182
+ className="flex-1 p-2 rounded-md border border-red-200 dark:border-red-800 dark:bg-red-900/30"
183
+ />
184
+ <button className="bg-red-500 text-white px-4 py-2 rounded-md hover:bg-red-600 transition-colors">
185
+ Delete Account
186
+ </button>
187
+ </div>
188
+ </div>
189
+ </div>
190
+ </div>
191
+ )}
192
+ </motion.div>
193
+ );
194
+ };
195
+
196
+ const Tabs = ({
197
+ tabs,
198
+ selectedTabIndex,
199
+ setSelectedTab,
200
+ }: {
201
+ tabs: Tab[];
202
+ selectedTabIndex: number;
203
+ setSelectedTab: (input: [number, number]) => void;
204
+ }) => {
205
+ const [buttonRefs, setButtonRefs] = React.useState<
206
+ Array<HTMLButtonElement | null>
207
+ >([]);
208
+
209
+ React.useEffect(() => {
210
+ setButtonRefs((prev) => prev.slice(0, tabs.length));
211
+ }, [tabs.length]);
212
+
213
+ const navRef = React.useRef<HTMLDivElement>(null);
214
+ const navRect = navRef.current?.getBoundingClientRect();
215
+
216
+ const selectedRect = buttonRefs[selectedTabIndex]?.getBoundingClientRect();
217
+
218
+ const [hoveredTabIndex, setHoveredTabIndex] = React.useState<number | null>(
219
+ null,
220
+ );
221
+ const hoveredRect =
222
+ buttonRefs[hoveredTabIndex ?? -1]?.getBoundingClientRect();
223
+
224
+ return (
225
+ <nav
226
+ ref={navRef}
227
+ className="flex flex-shrink-0 justify-center items-center relative z-0 py-2"
228
+ onPointerLeave={() => setHoveredTabIndex(null)}
229
+ >
230
+ {tabs.map((item, i) => {
231
+ const isActive = selectedTabIndex === i;
232
+
233
+ return (
234
+ <button
235
+ key={item.value}
236
+ className="text-sm relative rounded-md flex items-center h-8 px-4 z-20 bg-transparent cursor-pointer select-none transition-colors"
237
+ onPointerEnter={() => setHoveredTabIndex(i)}
238
+ onFocus={() => setHoveredTabIndex(i)}
239
+ onClick={() => setSelectedTab([i, i > selectedTabIndex ? 1 : -1])}
240
+ >
241
+ <motion.span
242
+ ref={(el) => {
243
+ buttonRefs[i] = el as HTMLButtonElement;
244
+ }}
245
+ className={cn("block", {
246
+ "text-gray-500": !isActive,
247
+ "text-gray-800 dark:text-white font-semibold": isActive,
248
+ })}
249
+ >
250
+ <small
251
+ className={item.value === "danger-zone" ? "text-red-500" : ""}
252
+ >
253
+ {item.label}
254
+ </small>
255
+ </motion.span>
256
+ </button>
257
+ );
258
+ })}
259
+
260
+ <AnimatePresence>
261
+ {hoveredRect && navRect && (
262
+ <motion.div
263
+ key="hover"
264
+ className={`absolute z-10 top-0 left-0 rounded-md ${
265
+ hoveredTabIndex ===
266
+ tabs.findIndex(({ value }) => value === "danger-zone")
267
+ ? "bg-red-500/50"
268
+ : "bg-gray-100/50"
269
+ }`}
270
+ initial={{
271
+ ...getHoverAnimationProps(hoveredRect, navRect),
272
+ opacity: 0,
273
+ }}
274
+ animate={{
275
+ ...getHoverAnimationProps(hoveredRect, navRect),
276
+ opacity: 1,
277
+ }}
278
+ exit={{
279
+ ...getHoverAnimationProps(hoveredRect, navRect),
280
+ opacity: 0,
281
+ }}
282
+ transition={transition}
283
+ />
284
+ )}
285
+ </AnimatePresence>
286
+
287
+ <AnimatePresence>
288
+ {selectedRect && navRect && (
289
+ <motion.div
290
+ className={`absolute z-10 bottom-0 left-0 h-[2px] ${
291
+ selectedTabIndex ===
292
+ tabs.findIndex(({ value }) => value === "danger-zone")
293
+ ? "bg-red-500"
294
+ : "bg-cyan-700"
295
+ }`}
296
+ initial={false}
297
+ animate={{
298
+ width: selectedRect.width + 18,
299
+ x: `calc(${selectedRect.left - navRect.left - 9}px)`,
300
+ opacity: 1,
301
+ }}
302
+ transition={transition}
303
+ />
304
+ )}
305
+ </AnimatePresence>
306
+ </nav>
307
+ );
308
+ };
309
+
310
+ export function AnimatedTabs({ tabs }: AnimatedTabsProps) {
311
+ const [hookProps] = React.useState(() => {
312
+ const initialTabId =
313
+ tabs.find((tab) => tab.value === "home")?.value || tabs[0].value;
314
+
315
+ return {
316
+ tabs: tabs.map(({ label, value, subRoutes }) => ({
317
+ label,
318
+ value,
319
+ subRoutes,
320
+ })),
321
+ initialTabId,
322
+ };
323
+ });
324
+
325
+ const framer = useTabs(hookProps);
326
+
327
+ return (
328
+ <div className="w-full">
329
+ <div className="relative flex w-full shrink-0 items-center justify-between overflow-x-auto overflow-y-hidden">
330
+ <Tabs {...framer.tabProps} />
331
+ </div>
332
+ <AnimatePresence mode="wait">
333
+ <TabContent tab={framer.selectedTab} />
334
+ </AnimatePresence>
335
+ </div>
336
+ );
337
+ }
338
+
339
+ // Standard Radix UI Tabs Components
340
+ const TabsRoot = React.forwardRef<
341
+ React.ElementRef<typeof TabsPrimitive.Root>,
342
+ React.ComponentPropsWithoutRef<typeof TabsPrimitive.Root>
343
+ >(({ className, ...props }, ref) => (
344
+ <TabsPrimitive.Root
345
+ ref={ref}
346
+ className={cn("w-full", className)}
347
+ {...props}
348
+ />
349
+ ));
350
+ TabsRoot.displayName = TabsPrimitive.Root.displayName;
7
351
 
8
352
  const TabsList = React.forwardRef<
9
353
  React.ElementRef<typeof TabsPrimitive.List>,
@@ -27,7 +371,7 @@ const TabsTrigger = React.forwardRef<
27
371
  <TabsPrimitive.Trigger
28
372
  ref={ref}
29
373
  className={cn(
30
- "inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-xs",
374
+ "inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",
31
375
  className,
32
376
  )}
33
377
  {...props}
@@ -42,7 +386,7 @@ const TabsContent = React.forwardRef<
42
386
  <TabsPrimitive.Content
43
387
  ref={ref}
44
388
  className={cn(
45
- "mt-2 ring-offset-background focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
389
+ "mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
46
390
  className,
47
391
  )}
48
392
  {...props}
@@ -50,4 +394,5 @@ const TabsContent = React.forwardRef<
50
394
  ));
51
395
  TabsContent.displayName = TabsPrimitive.Content.displayName;
52
396
 
53
- export { Tabs, TabsList, TabsTrigger, TabsContent };
397
+ // Export standard Radix UI tabs components
398
+ export { TabsRoot as Tabs, TabsList, TabsTrigger, TabsContent };
@@ -1,11 +1,10 @@
1
1
  import * as React from "react";
2
- import * as TogglePrimitive from "@radix-ui/react-toggle";
3
2
  import { cva, type VariantProps } from "class-variance-authority";
4
-
5
- import { cn } from "@/lib/utils";
3
+ import { cn } from "../../lib/utils";
4
+ import { useSegmentedControl } from "../../hooks/use-segmented-control";
6
5
 
7
6
  const toggleVariants = cva(
8
- "inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground",
7
+ "inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground",
9
8
  {
10
9
  variants: {
11
10
  variant: {
@@ -26,18 +25,71 @@ const toggleVariants = cva(
26
25
  },
27
26
  );
28
27
 
29
- const Toggle = React.forwardRef<
30
- React.ElementRef<typeof TogglePrimitive.Root>,
31
- React.ComponentPropsWithoutRef<typeof TogglePrimitive.Root> &
32
- VariantProps<typeof toggleVariants>
33
- >(({ className, variant, size, ...props }, ref) => (
34
- <TogglePrimitive.Root
35
- ref={ref}
36
- className={cn(toggleVariants({ variant, size, className }))}
37
- {...props}
38
- />
39
- ));
40
-
41
- Toggle.displayName = TogglePrimitive.Root.displayName;
42
-
43
- export { Toggle, toggleVariants };
28
+ // Segmented Control Component
29
+ export interface SegmentedControlProps<T extends string = string>
30
+ extends React.HTMLAttributes<HTMLDivElement> {
31
+ options: Array<{ label: React.ReactNode; value: T }>;
32
+ value?: T;
33
+ defaultValue?: T;
34
+ onValueChange?: (value: T) => void;
35
+ }
36
+
37
+ const SegmentedControlInner = React.forwardRef<
38
+ HTMLDivElement,
39
+ SegmentedControlProps
40
+ >(
41
+ (
42
+ { className, options, value, defaultValue, onValueChange, ...props },
43
+ ref,
44
+ ) => {
45
+ const { value: selectedValue, onValueChange: handleValueChange } =
46
+ useSegmentedControl({
47
+ value,
48
+ defaultValue: defaultValue ?? options[0]?.value,
49
+ onValueChange,
50
+ });
51
+
52
+ return (
53
+ <div ref={ref} className={cn(className)} {...props}>
54
+ {options.map((option) => {
55
+ const isReactElement = React.isValidElement(option.label);
56
+
57
+ return (
58
+ <button
59
+ key={option.value}
60
+ className={cn(
61
+ "inline-flex items-center justify-center h-8 px-6 rounded-full transition-all focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring",
62
+ selectedValue === option.value
63
+ ? "bg-cyan-700 text-white font-semibold"
64
+ : "text-gray-600 hover:bg-gray-50 font-medium",
65
+ )}
66
+ onClick={() => handleValueChange(option.value)}
67
+ type="button"
68
+ data-active={selectedValue === option.value}
69
+ >
70
+ {isReactElement ? (
71
+ option.label
72
+ ) : (
73
+ <span className="body-small font-medium">{option.label}</span>
74
+ )}
75
+ </button>
76
+ );
77
+ })}
78
+ </div>
79
+ );
80
+ },
81
+ );
82
+
83
+ SegmentedControlInner.displayName = "SegmentedControl";
84
+
85
+ export const SegmentedControl = SegmentedControlInner as <
86
+ T extends string = string,
87
+ >(
88
+ props: SegmentedControlProps<T> & { ref?: React.Ref<HTMLDivElement> },
89
+ ) => React.ReactElement;
90
+
91
+ // Main Toggle export for backward compatibility
92
+ export const Toggle = SegmentedControl;
93
+
94
+ export { toggleVariants };
95
+ export type { VariantProps };
@@ -1,28 +1,79 @@
1
+ "use client";
2
+
1
3
  import * as React from "react";
2
4
  import * as TooltipPrimitive from "@radix-ui/react-tooltip";
3
5
 
4
6
  import { cn } from "@/lib/utils";
5
7
 
6
- const TooltipProvider = TooltipPrimitive.Provider;
8
+ function TooltipProvider({
9
+ delayDuration = 0,
10
+ ...props
11
+ }: React.ComponentProps<typeof TooltipPrimitive.Provider>) {
12
+ return (
13
+ <TooltipPrimitive.Provider
14
+ data-slot="tooltip-provider"
15
+ delayDuration={delayDuration}
16
+ {...props}
17
+ />
18
+ );
19
+ }
7
20
 
8
- const Tooltip = TooltipPrimitive.Root;
21
+ function Tooltip({
22
+ ...props
23
+ }: React.ComponentProps<typeof TooltipPrimitive.Root>) {
24
+ return (
25
+ <TooltipProvider>
26
+ <TooltipPrimitive.Root data-slot="tooltip" {...props} />
27
+ </TooltipProvider>
28
+ );
29
+ }
9
30
 
10
- const TooltipTrigger = TooltipPrimitive.Trigger;
31
+ function TooltipTrigger({
32
+ ...props
33
+ }: React.ComponentProps<typeof TooltipPrimitive.Trigger>) {
34
+ return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />;
35
+ }
11
36
 
12
- const TooltipContent = React.forwardRef<
13
- React.ElementRef<typeof TooltipPrimitive.Content>,
14
- React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
15
- >(({ className, sideOffset = 4, ...props }, ref) => (
16
- <TooltipPrimitive.Content
17
- ref={ref}
18
- sideOffset={sideOffset}
19
- className={cn(
20
- "z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
21
- className,
22
- )}
23
- {...props}
24
- />
25
- ));
26
- TooltipContent.displayName = TooltipPrimitive.Content.displayName;
37
+ function TooltipContent({
38
+ className,
39
+ sideOffset = 0,
40
+ side = "bottom",
41
+ children,
42
+ alignOffset = 0,
43
+ ...props
44
+ }: React.ComponentProps<typeof TooltipPrimitive.Content>) {
45
+ return (
46
+ <TooltipPrimitive.Portal>
47
+ <TooltipPrimitive.Content
48
+ data-slot="tooltip-content"
49
+ sideOffset={sideOffset}
50
+ alignOffset={alignOffset}
51
+ side={side}
52
+ className={cn(
53
+ "group relative bg-gray-700 animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-lg px-6 pt-8 pb-6 text-balance shadow-sm",
54
+ className,
55
+ )}
56
+ {...props}
57
+ >
58
+ {/* Marker/Arrow */}
59
+ <div className="absolute left-1/2 -translate-x-1/2 flex justify-center group-data-[side=top]:bottom-0 group-data-[side=top]:rotate-180 group-data-[side=bottom]:top-0 group-data-[side=left]:right-0 group-data-[side=right]:left-0">
60
+ <svg
61
+ xmlns="http://www.w3.org/2000/svg"
62
+ width="10"
63
+ height="5"
64
+ viewBox="0 0 10 5"
65
+ fill="none"
66
+ >
67
+ <path
68
+ d="M10 -1.74846e-06L-7.36867e-07 0C-3.29906e-07 2.76142 2.23858 5 5 5C7.76142 5 10 2.76142 10 -1.74846e-06Z"
69
+ fill="#39C9EA"
70
+ />
71
+ </svg>
72
+ </div>
73
+ {children}
74
+ </TooltipPrimitive.Content>
75
+ </TooltipPrimitive.Portal>
76
+ );
77
+ }
27
78
 
28
79
  export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };