@tuturuuu/ui 0.0.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 (104) hide show
  1. package/.checksum +1 -0
  2. package/README.md +46 -0
  3. package/components.json +20 -0
  4. package/eslint.config.mjs +20 -0
  5. package/jsr.json +10 -0
  6. package/package.json +120 -0
  7. package/postcss.config.mjs +8 -0
  8. package/rollup.config.js +40 -0
  9. package/src/components/ui/accordion.tsx +70 -0
  10. package/src/components/ui/alert-dialog.tsx +156 -0
  11. package/src/components/ui/alert.tsx +58 -0
  12. package/src/components/ui/aspect-ratio.tsx +11 -0
  13. package/src/components/ui/avatar.tsx +52 -0
  14. package/src/components/ui/badge.tsx +49 -0
  15. package/src/components/ui/breadcrumb.tsx +108 -0
  16. package/src/components/ui/button.tsx +61 -0
  17. package/src/components/ui/calendar.tsx +212 -0
  18. package/src/components/ui/card.tsx +74 -0
  19. package/src/components/ui/carousel.tsx +240 -0
  20. package/src/components/ui/chart.tsx +365 -0
  21. package/src/components/ui/checkbox.tsx +31 -0
  22. package/src/components/ui/codeblock.tsx +161 -0
  23. package/src/components/ui/collapsible.tsx +33 -0
  24. package/src/components/ui/color-picker.tsx +143 -0
  25. package/src/components/ui/command.tsx +176 -0
  26. package/src/components/ui/context-menu.tsx +251 -0
  27. package/src/components/ui/custom/autosize-textarea.tsx +111 -0
  28. package/src/components/ui/custom/calendar/core.tsx +61 -0
  29. package/src/components/ui/custom/calendar/day-cell.tsx +74 -0
  30. package/src/components/ui/custom/calendar/month-header.tsx +59 -0
  31. package/src/components/ui/custom/calendar/month-view.tsx +110 -0
  32. package/src/components/ui/custom/calendar/utils.ts +76 -0
  33. package/src/components/ui/custom/calendar/year-calendar.tsx +64 -0
  34. package/src/components/ui/custom/calendar/year-view.tsx +58 -0
  35. package/src/components/ui/custom/combobox.tsx +197 -0
  36. package/src/components/ui/custom/common-footer.tsx +215 -0
  37. package/src/components/ui/custom/compared-date-range-picker.tsx +561 -0
  38. package/src/components/ui/custom/date-input.tsx +279 -0
  39. package/src/components/ui/custom/empty-card.tsx +39 -0
  40. package/src/components/ui/custom/feature-summary.tsx +135 -0
  41. package/src/components/ui/custom/file-uploader.tsx +349 -0
  42. package/src/components/ui/custom/input-field.tsx +29 -0
  43. package/src/components/ui/custom/loading-indicator.tsx +28 -0
  44. package/src/components/ui/custom/modifiable-dialog-trigger.tsx +83 -0
  45. package/src/components/ui/custom/month-picker.tsx +157 -0
  46. package/src/components/ui/custom/report-preview.tsx +175 -0
  47. package/src/components/ui/custom/search-bar.tsx +56 -0
  48. package/src/components/ui/custom/select-field.tsx +78 -0
  49. package/src/components/ui/custom/tables/data-table-column-header.tsx +72 -0
  50. package/src/components/ui/custom/tables/data-table-create-button.tsx +31 -0
  51. package/src/components/ui/custom/tables/data-table-faceted-filter.tsx +142 -0
  52. package/src/components/ui/custom/tables/data-table-pagination.tsx +243 -0
  53. package/src/components/ui/custom/tables/data-table-refresh-button.tsx +45 -0
  54. package/src/components/ui/custom/tables/data-table-toolbar.tsx +133 -0
  55. package/src/components/ui/custom/tables/data-table-view-options.tsx +112 -0
  56. package/src/components/ui/custom/tables/data-table.tsx +228 -0
  57. package/src/components/ui/custom/uploaded-files-card.tsx +50 -0
  58. package/src/components/ui/dialog.tsx +137 -0
  59. package/src/components/ui/drawer.tsx +131 -0
  60. package/src/components/ui/dropdown-menu.tsx +256 -0
  61. package/src/components/ui/form.tsx +167 -0
  62. package/src/components/ui/hover-card.tsx +41 -0
  63. package/src/components/ui/icons.tsx +506 -0
  64. package/src/components/ui/input-otp.tsx +78 -0
  65. package/src/components/ui/input.tsx +18 -0
  66. package/src/components/ui/label.tsx +23 -0
  67. package/src/components/ui/markdown.tsx +7 -0
  68. package/src/components/ui/menubar.tsx +275 -0
  69. package/src/components/ui/navigation-menu.tsx +169 -0
  70. package/src/components/ui/pagination.tsx +126 -0
  71. package/src/components/ui/popover.tsx +47 -0
  72. package/src/components/ui/progress.tsx +30 -0
  73. package/src/components/ui/radio-group.tsx +44 -0
  74. package/src/components/ui/resizable.tsx +55 -0
  75. package/src/components/ui/scroll-area.tsx +57 -0
  76. package/src/components/ui/select.tsx +180 -0
  77. package/src/components/ui/separator.tsx +27 -0
  78. package/src/components/ui/sheet.tsx +138 -0
  79. package/src/components/ui/sidebar.tsx +734 -0
  80. package/src/components/ui/skeleton.tsx +13 -0
  81. package/src/components/ui/slider.tsx +62 -0
  82. package/src/components/ui/sonner.tsx +29 -0
  83. package/src/components/ui/switch.tsx +30 -0
  84. package/src/components/ui/table.tsx +112 -0
  85. package/src/components/ui/tabs.tsx +68 -0
  86. package/src/components/ui/tag-input.tsx +141 -0
  87. package/src/components/ui/textarea.tsx +17 -0
  88. package/src/components/ui/time-picker-input.tsx +117 -0
  89. package/src/components/ui/time-picker-utils.tsx +146 -0
  90. package/src/components/ui/toast.tsx +128 -0
  91. package/src/components/ui/toaster.tsx +35 -0
  92. package/src/components/ui/toggle-group.tsx +72 -0
  93. package/src/components/ui/toggle.tsx +46 -0
  94. package/src/components/ui/tooltip.tsx +60 -0
  95. package/src/globals.css +252 -0
  96. package/src/hooks/use-callback-ref.ts +28 -0
  97. package/src/hooks/use-controllable-state.ts +68 -0
  98. package/src/hooks/use-copy-to-clipboard.ts +46 -0
  99. package/src/hooks/use-form.ts +23 -0
  100. package/src/hooks/use-forwarded-ref.ts +17 -0
  101. package/src/hooks/use-mobile.tsx +21 -0
  102. package/src/hooks/use-toast.ts +191 -0
  103. package/src/resolvers.ts +3 -0
  104. package/tsconfig.json +17 -0
@@ -0,0 +1,146 @@
1
+ /**
2
+ * regular expression to check for valid hour format (01-23)
3
+ */
4
+ export function isValidHour(value: string) {
5
+ return /^(0[0-9]|1[0-9]|2[0-3])$/.test(value);
6
+ }
7
+
8
+ /**
9
+ * regular expression to check for valid 12-hour format (01-12)
10
+ */
11
+ export function isValid12Hour(value: string) {
12
+ return /^(0[1-9]|1[0-2])$/.test(value);
13
+ }
14
+
15
+ /**
16
+ * regular expression to check for valid minute format (00-59)
17
+ */
18
+ export function isValidMinuteOrSecond(value: string) {
19
+ return /^[0-5][0-9]$/.test(value);
20
+ }
21
+
22
+ type GetValidNumberConfig = { max: number; min?: number; loop?: boolean };
23
+
24
+ export function getValidNumber(
25
+ value: string,
26
+ { max, min = 0, loop = false }: GetValidNumberConfig
27
+ ) {
28
+ let numericValue = parseInt(value, 10);
29
+
30
+ if (!isNaN(numericValue)) {
31
+ if (!loop) {
32
+ if (numericValue > max) numericValue = max;
33
+ if (numericValue < min) numericValue = min;
34
+ } else {
35
+ if (numericValue > max) numericValue = min;
36
+ if (numericValue < min) numericValue = max;
37
+ }
38
+ return numericValue.toString().padStart(2, '0');
39
+ }
40
+
41
+ return '00';
42
+ }
43
+
44
+ export function getValidHour(value: string) {
45
+ if (isValidHour(value)) return value;
46
+ return getValidNumber(value, { max: 23 });
47
+ }
48
+
49
+ export function getValid12Hour(value: string) {
50
+ if (isValid12Hour(value)) return value;
51
+ return getValidNumber(value, { max: 12 });
52
+ }
53
+
54
+ export function getValidMinuteOrSecond(value: string) {
55
+ if (isValidMinuteOrSecond(value)) return value;
56
+ return getValidNumber(value, { max: 59 });
57
+ }
58
+
59
+ type GetValidArrowNumberConfig = {
60
+ min: number;
61
+ max: number;
62
+ step: number;
63
+ };
64
+
65
+ export function getValidArrowNumber(
66
+ value: string,
67
+ { min, max, step }: GetValidArrowNumberConfig
68
+ ) {
69
+ let numericValue = parseInt(value, 10);
70
+ if (!isNaN(numericValue)) {
71
+ numericValue += step;
72
+ return getValidNumber(String(numericValue), { min, max, loop: true });
73
+ }
74
+ return '00';
75
+ }
76
+
77
+ export function getValidArrowHour(value: string, step: number) {
78
+ return getValidArrowNumber(value, { min: 0, max: 23, step });
79
+ }
80
+
81
+ export function getValidArrowMinuteOrSecond(value: string, step: number) {
82
+ return getValidArrowNumber(value, { min: 0, max: 59, step });
83
+ }
84
+
85
+ export function setMinutes(date: Date, value: string) {
86
+ const minutes = getValidMinuteOrSecond(value);
87
+ date.setMinutes(parseInt(minutes, 10));
88
+ return date;
89
+ }
90
+
91
+ export function setSeconds(date: Date, value: string) {
92
+ const seconds = getValidMinuteOrSecond(value);
93
+ date.setSeconds(parseInt(seconds, 10));
94
+ return date;
95
+ }
96
+
97
+ export function setHours(date: Date, value: string) {
98
+ const hours = getValidHour(value);
99
+ date.setHours(parseInt(hours, 10));
100
+ return date;
101
+ }
102
+
103
+ export type TimePickerType = 'minutes' | 'seconds' | 'hours'; // | "12hours";
104
+
105
+ export function setDateByType(date: Date, value: string, type: TimePickerType) {
106
+ switch (type) {
107
+ case 'minutes':
108
+ return setMinutes(date, value);
109
+ case 'seconds':
110
+ return setSeconds(date, value);
111
+ case 'hours':
112
+ return setHours(date, value);
113
+ default:
114
+ return date;
115
+ }
116
+ }
117
+
118
+ export function getDateByType(date: Date, type: TimePickerType) {
119
+ switch (type) {
120
+ case 'minutes':
121
+ return getValidMinuteOrSecond(String(date.getMinutes()));
122
+ case 'seconds':
123
+ return getValidMinuteOrSecond(String(date.getSeconds()));
124
+ case 'hours':
125
+ return getValidHour(String(date.getHours()));
126
+ default:
127
+ return '00';
128
+ }
129
+ }
130
+
131
+ export function getArrowByType(
132
+ value: string,
133
+ step: number,
134
+ type: TimePickerType
135
+ ) {
136
+ switch (type) {
137
+ case 'minutes':
138
+ return getValidArrowMinuteOrSecond(value, step);
139
+ case 'seconds':
140
+ return getValidArrowMinuteOrSecond(value, step);
141
+ case 'hours':
142
+ return getValidArrowHour(value, step);
143
+ default:
144
+ return '00';
145
+ }
146
+ }
@@ -0,0 +1,128 @@
1
+ 'use client';
2
+
3
+ import * as ToastPrimitives from '@radix-ui/react-toast';
4
+ import { cn } from '@tuturuuu/utils/format';
5
+ import { type VariantProps, cva } from 'class-variance-authority';
6
+ import { X } from 'lucide-react';
7
+ import * as React from 'react';
8
+
9
+ const ToastProvider = ToastPrimitives.Provider;
10
+
11
+ const ToastViewport = React.forwardRef<
12
+ React.ComponentRef<typeof ToastPrimitives.Viewport>,
13
+ React.ComponentPropsWithoutRef<typeof ToastPrimitives.Viewport>
14
+ >(({ className, ...props }, ref) => (
15
+ <ToastPrimitives.Viewport
16
+ ref={ref}
17
+ className={cn(
18
+ 'fixed top-0 z-[100] flex max-h-screen w-full flex-col-reverse p-4 sm:top-auto sm:right-0 sm:bottom-0 sm:flex-col md:max-w-[420px]',
19
+ className
20
+ )}
21
+ {...props}
22
+ />
23
+ ));
24
+ ToastViewport.displayName = ToastPrimitives.Viewport.displayName;
25
+
26
+ const toastVariants = cva(
27
+ 'group pointer-events-auto relative flex w-full items-center justify-between space-x-4 overflow-hidden rounded-md border p-6 pr-8 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full',
28
+ {
29
+ variants: {
30
+ variant: {
31
+ default: 'border bg-background text-foreground',
32
+ destructive:
33
+ 'destructive group border-destructive bg-destructive text-destructive-foreground',
34
+ },
35
+ },
36
+ defaultVariants: {
37
+ variant: 'default',
38
+ },
39
+ }
40
+ );
41
+
42
+ const Toast = React.forwardRef<
43
+ React.ComponentRef<typeof ToastPrimitives.Root>,
44
+ React.ComponentPropsWithoutRef<typeof ToastPrimitives.Root> &
45
+ VariantProps<typeof toastVariants>
46
+ >(({ className, variant, ...props }, ref) => {
47
+ return (
48
+ <ToastPrimitives.Root
49
+ ref={ref}
50
+ className={cn(toastVariants({ variant }), className)}
51
+ {...props}
52
+ />
53
+ );
54
+ });
55
+ Toast.displayName = ToastPrimitives.Root.displayName;
56
+
57
+ const ToastAction = React.forwardRef<
58
+ React.ComponentRef<typeof ToastPrimitives.Action>,
59
+ React.ComponentPropsWithoutRef<typeof ToastPrimitives.Action>
60
+ >(({ className, ...props }, ref) => (
61
+ <ToastPrimitives.Action
62
+ ref={ref}
63
+ className={cn(
64
+ 'inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-sm font-medium ring-offset-background transition-colors group-[.destructive]:border-muted/40 hover:bg-secondary group-[.destructive]:hover:border-destructive/30 group-[.destructive]:hover:bg-destructive group-[.destructive]:hover:text-destructive-foreground focus:ring-2 focus:ring-ring focus:ring-offset-2 focus:outline-hidden group-[.destructive]:focus:ring-destructive disabled:pointer-events-none disabled:opacity-50',
65
+ className
66
+ )}
67
+ {...props}
68
+ />
69
+ ));
70
+ ToastAction.displayName = ToastPrimitives.Action.displayName;
71
+
72
+ const ToastClose = React.forwardRef<
73
+ React.ComponentRef<typeof ToastPrimitives.Close>,
74
+ React.ComponentPropsWithoutRef<typeof ToastPrimitives.Close>
75
+ >(({ className, ...props }, ref) => (
76
+ <ToastPrimitives.Close
77
+ ref={ref}
78
+ className={cn(
79
+ 'absolute top-2 right-2 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity group-hover:opacity-100 group-[.destructive]:text-red-300 hover:text-foreground group-[.destructive]:hover:text-red-50 focus:opacity-100 focus:ring-2 focus:outline-hidden group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600',
80
+ className
81
+ )}
82
+ toast-close=""
83
+ {...props}
84
+ >
85
+ <X className="h-4 w-4" />
86
+ </ToastPrimitives.Close>
87
+ ));
88
+ ToastClose.displayName = ToastPrimitives.Close.displayName;
89
+
90
+ const ToastTitle = React.forwardRef<
91
+ React.ComponentRef<typeof ToastPrimitives.Title>,
92
+ React.ComponentPropsWithoutRef<typeof ToastPrimitives.Title>
93
+ >(({ className, ...props }, ref) => (
94
+ <ToastPrimitives.Title
95
+ ref={ref}
96
+ className={cn('text-sm font-semibold', className)}
97
+ {...props}
98
+ />
99
+ ));
100
+ ToastTitle.displayName = ToastPrimitives.Title.displayName;
101
+
102
+ const ToastDescription = React.forwardRef<
103
+ React.ComponentRef<typeof ToastPrimitives.Description>,
104
+ React.ComponentPropsWithoutRef<typeof ToastPrimitives.Description>
105
+ >(({ className, ...props }, ref) => (
106
+ <ToastPrimitives.Description
107
+ ref={ref}
108
+ className={cn('text-sm opacity-90', className)}
109
+ {...props}
110
+ />
111
+ ));
112
+ ToastDescription.displayName = ToastPrimitives.Description.displayName;
113
+
114
+ type ToastProps = React.ComponentPropsWithoutRef<typeof Toast>;
115
+
116
+ type ToastActionElement = React.ReactElement<typeof ToastAction>;
117
+
118
+ export {
119
+ Toast,
120
+ ToastAction,
121
+ ToastClose,
122
+ ToastDescription,
123
+ ToastProvider,
124
+ ToastTitle,
125
+ ToastViewport,
126
+ type ToastActionElement,
127
+ type ToastProps,
128
+ };
@@ -0,0 +1,35 @@
1
+ 'use client';
2
+
3
+ import { useToast } from '../../hooks/use-toast';
4
+ import {
5
+ Toast,
6
+ ToastClose,
7
+ ToastDescription,
8
+ ToastProvider,
9
+ ToastTitle,
10
+ ToastViewport,
11
+ } from './toast';
12
+
13
+ export function Toaster() {
14
+ const { toasts } = useToast();
15
+
16
+ return (
17
+ <ToastProvider>
18
+ {toasts.map(function ({ id, title, description, action, ...props }) {
19
+ return (
20
+ <Toast key={id} {...props}>
21
+ <div className="grid gap-1">
22
+ {title && <ToastTitle>{title}</ToastTitle>}
23
+ {description && (
24
+ <ToastDescription>{description}</ToastDescription>
25
+ )}
26
+ </div>
27
+ {action}
28
+ <ToastClose />
29
+ </Toast>
30
+ );
31
+ })}
32
+ <ToastViewport />
33
+ </ToastProvider>
34
+ );
35
+ }
@@ -0,0 +1,72 @@
1
+ 'use client';
2
+
3
+ import { toggleVariants } from './toggle';
4
+ import * as ToggleGroupPrimitive from '@radix-ui/react-toggle-group';
5
+ import { cn } from '@tuturuuu/utils/format';
6
+ import { type VariantProps } from 'class-variance-authority';
7
+ import * as React from 'react';
8
+
9
+ const ToggleGroupContext = React.createContext<
10
+ VariantProps<typeof toggleVariants>
11
+ >({
12
+ size: 'default',
13
+ variant: 'default',
14
+ });
15
+
16
+ function ToggleGroup({
17
+ className,
18
+ variant,
19
+ size,
20
+ children,
21
+ ...props
22
+ }: React.ComponentProps<typeof ToggleGroupPrimitive.Root> &
23
+ VariantProps<typeof toggleVariants>) {
24
+ return (
25
+ <ToggleGroupPrimitive.Root
26
+ data-slot="toggle-group"
27
+ data-variant={variant}
28
+ data-size={size}
29
+ className={cn(
30
+ 'group/toggle-group flex items-center justify-center rounded-md data-[variant=outline]:shadow-xs',
31
+ className
32
+ )}
33
+ {...props}
34
+ >
35
+ <ToggleGroupContext.Provider value={{ variant, size }}>
36
+ {children}
37
+ </ToggleGroupContext.Provider>
38
+ </ToggleGroupPrimitive.Root>
39
+ );
40
+ }
41
+
42
+ function ToggleGroupItem({
43
+ className,
44
+ children,
45
+ variant,
46
+ size,
47
+ ...props
48
+ }: React.ComponentProps<typeof ToggleGroupPrimitive.Item> &
49
+ VariantProps<typeof toggleVariants>) {
50
+ const context = React.useContext(ToggleGroupContext);
51
+
52
+ return (
53
+ <ToggleGroupPrimitive.Item
54
+ data-slot="toggle-group-item"
55
+ data-variant={context.variant || variant}
56
+ data-size={context.size || size}
57
+ className={cn(
58
+ toggleVariants({
59
+ variant: context.variant || variant,
60
+ size: context.size || size,
61
+ }),
62
+ 'min-w-0 shrink-0 rounded-none shadow-none first:rounded-l-md last:rounded-r-md focus:z-10 focus-visible:z-10 data-[variant=outline]:border-l-0 data-[variant=outline]:first:border-l',
63
+ className
64
+ )}
65
+ {...props}
66
+ >
67
+ {children}
68
+ </ToggleGroupPrimitive.Item>
69
+ );
70
+ }
71
+
72
+ export { ToggleGroup, ToggleGroupItem };
@@ -0,0 +1,46 @@
1
+ 'use client';
2
+
3
+ import * as TogglePrimitive from '@radix-ui/react-toggle';
4
+ import { cn } from '@tuturuuu/utils/format';
5
+ import { type VariantProps, cva } from 'class-variance-authority';
6
+ import * as React from 'react';
7
+
8
+ const toggleVariants = cva(
9
+ "inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium transition-colors hover:bg-muted hover:text-muted-foreground disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 ring-ring/10 dark:ring-ring/20 dark:outline-ring/40 outline-ring/50 focus-visible:ring-4 focus-visible:outline-1 aria-invalid:focus-visible:ring-0 transition-[color,box-shadow]",
10
+ {
11
+ variants: {
12
+ variant: {
13
+ default: 'bg-transparent',
14
+ outline:
15
+ 'border border-input bg-transparent shadow-xs hover:bg-accent hover:text-accent-foreground',
16
+ },
17
+ size: {
18
+ default: 'h-9 px-2 min-w-9',
19
+ sm: 'h-8 px-1.5 min-w-8',
20
+ lg: 'h-10 px-2.5 min-w-10',
21
+ },
22
+ },
23
+ defaultVariants: {
24
+ variant: 'default',
25
+ size: 'default',
26
+ },
27
+ }
28
+ );
29
+
30
+ function Toggle({
31
+ className,
32
+ variant,
33
+ size,
34
+ ...props
35
+ }: React.ComponentProps<typeof TogglePrimitive.Root> &
36
+ VariantProps<typeof toggleVariants>) {
37
+ return (
38
+ <TogglePrimitive.Root
39
+ data-slot="toggle"
40
+ className={cn(toggleVariants({ variant, size, className }))}
41
+ {...props}
42
+ />
43
+ );
44
+ }
45
+
46
+ export { Toggle, toggleVariants };
@@ -0,0 +1,60 @@
1
+ 'use client';
2
+
3
+ import * as TooltipPrimitive from '@radix-ui/react-tooltip';
4
+ import { cn } from '@tuturuuu/utils/format';
5
+ import * as React from 'react';
6
+
7
+ function TooltipProvider({
8
+ delayDuration = 0,
9
+ ...props
10
+ }: React.ComponentProps<typeof TooltipPrimitive.Provider>) {
11
+ return (
12
+ <TooltipPrimitive.Provider
13
+ data-slot="tooltip-provider"
14
+ delayDuration={delayDuration}
15
+ {...props}
16
+ />
17
+ );
18
+ }
19
+
20
+ function Tooltip({
21
+ ...props
22
+ }: React.ComponentProps<typeof TooltipPrimitive.Root>) {
23
+ return (
24
+ <TooltipProvider>
25
+ <TooltipPrimitive.Root data-slot="tooltip" {...props} />
26
+ </TooltipProvider>
27
+ );
28
+ }
29
+
30
+ function TooltipTrigger({
31
+ ...props
32
+ }: React.ComponentProps<typeof TooltipPrimitive.Trigger>) {
33
+ return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />;
34
+ }
35
+
36
+ function TooltipContent({
37
+ className,
38
+ sideOffset = 4,
39
+ children,
40
+ ...props
41
+ }: React.ComponentProps<typeof TooltipPrimitive.Content>) {
42
+ return (
43
+ <TooltipPrimitive.Portal>
44
+ <TooltipPrimitive.Content
45
+ data-slot="tooltip-content"
46
+ sideOffset={sideOffset}
47
+ className={cn(
48
+ 'z-50 max-w-sm rounded-md bg-primary px-3 py-1.5 text-xs text-primary-foreground animate-in fade-in-0 zoom-in-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 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95',
49
+ className
50
+ )}
51
+ {...props}
52
+ >
53
+ {children}
54
+ {/* <TooltipPrimitive.Arrow className="z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px] bg-primary fill-primary" /> */}
55
+ </TooltipPrimitive.Content>
56
+ </TooltipPrimitive.Portal>
57
+ );
58
+ }
59
+
60
+ export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger };