@dilipod/ui 0.2.14 → 0.3.0

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 (54) hide show
  1. package/dist/components/alert-dialog.d.ts +34 -0
  2. package/dist/components/alert-dialog.d.ts.map +1 -0
  3. package/dist/components/breadcrumbs.d.ts +30 -0
  4. package/dist/components/breadcrumbs.d.ts.map +1 -0
  5. package/dist/components/date-range-picker.d.ts +36 -0
  6. package/dist/components/date-range-picker.d.ts.map +1 -0
  7. package/dist/components/pagination.d.ts +29 -0
  8. package/dist/components/pagination.d.ts.map +1 -0
  9. package/dist/components/popover.d.ts +10 -0
  10. package/dist/components/popover.d.ts.map +1 -0
  11. package/dist/components/radio-group.d.ts +17 -0
  12. package/dist/components/radio-group.d.ts.map +1 -0
  13. package/dist/components/select.d.ts.map +1 -1
  14. package/dist/components/settings-nav.d.ts +35 -0
  15. package/dist/components/settings-nav.d.ts.map +1 -0
  16. package/dist/components/skeleton.d.ts +28 -0
  17. package/dist/components/skeleton.d.ts.map +1 -0
  18. package/dist/components/step-progress.d.ts +28 -0
  19. package/dist/components/step-progress.d.ts.map +1 -0
  20. package/dist/components/switch.d.ts +15 -0
  21. package/dist/components/switch.d.ts.map +1 -0
  22. package/dist/components/tabs.d.ts +10 -0
  23. package/dist/components/tabs.d.ts.map +1 -0
  24. package/dist/components/toast.d.ts +2 -2
  25. package/dist/components/toast.d.ts.map +1 -1
  26. package/dist/components/tooltip.d.ts +17 -0
  27. package/dist/components/tooltip.d.ts.map +1 -0
  28. package/dist/index.d.ts +22 -0
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +1273 -93
  31. package/dist/index.js.map +1 -1
  32. package/dist/index.mjs +1219 -95
  33. package/dist/index.mjs.map +1 -1
  34. package/package.json +10 -2
  35. package/src/components/alert-dialog.tsx +203 -0
  36. package/src/components/breadcrumbs.tsx +160 -0
  37. package/src/components/date-range-picker.tsx +183 -0
  38. package/src/components/dialog.stories.tsx +91 -0
  39. package/src/components/dialog.tsx +2 -2
  40. package/src/components/dropdown-menu.stories.tsx +102 -0
  41. package/src/components/dropdown-menu.tsx +2 -2
  42. package/src/components/pagination.tsx +220 -0
  43. package/src/components/popover.tsx +53 -0
  44. package/src/components/radio-group.tsx +125 -0
  45. package/src/components/select.tsx +2 -1
  46. package/src/components/settings-nav.tsx +137 -0
  47. package/src/components/skeleton.tsx +103 -0
  48. package/src/components/step-progress.tsx +205 -0
  49. package/src/components/switch.tsx +95 -0
  50. package/src/components/tabs.tsx +92 -0
  51. package/src/components/toast.tsx +4 -1
  52. package/src/components/tooltip.tsx +78 -0
  53. package/src/index.ts +78 -0
  54. package/src/styles/globals.css +99 -0
@@ -0,0 +1,103 @@
1
+ 'use client'
2
+
3
+ import * as React from 'react'
4
+ import { cn } from '../lib/utils'
5
+
6
+ export interface SkeletonProps extends React.HTMLAttributes<HTMLDivElement> {
7
+ /** Variant of the skeleton */
8
+ variant?: 'default' | 'circular' | 'rounded'
9
+ /** Width of the skeleton (can be number for px or string like '100%') */
10
+ width?: number | string
11
+ /** Height of the skeleton (can be number for px or string like '2rem') */
12
+ height?: number | string
13
+ /** Whether to show animation */
14
+ animate?: boolean
15
+ }
16
+
17
+ const Skeleton = React.forwardRef<HTMLDivElement, SkeletonProps>(
18
+ ({ className, variant = 'default', width, height, animate = true, style, ...props }, ref) => {
19
+ const variantStyles = {
20
+ default: 'rounded-sm',
21
+ circular: 'rounded-full',
22
+ rounded: 'rounded-md',
23
+ }
24
+
25
+ return (
26
+ <div
27
+ ref={ref}
28
+ className={cn(
29
+ 'bg-muted',
30
+ animate && 'animate-pulse',
31
+ variantStyles[variant],
32
+ className
33
+ )}
34
+ style={{
35
+ width: typeof width === 'number' ? `${width}px` : width,
36
+ height: typeof height === 'number' ? `${height}px` : height,
37
+ ...style,
38
+ }}
39
+ {...props}
40
+ />
41
+ )
42
+ }
43
+ )
44
+ Skeleton.displayName = 'Skeleton'
45
+
46
+ // Common skeleton patterns
47
+ export interface SkeletonTextProps extends Omit<SkeletonProps, 'variant'> {
48
+ /** Number of lines to render */
49
+ lines?: number
50
+ /** Gap between lines */
51
+ gap?: number
52
+ }
53
+
54
+ const SkeletonText = React.forwardRef<HTMLDivElement, SkeletonTextProps>(
55
+ ({ lines = 3, gap = 8, className, ...props }, ref) => {
56
+ return (
57
+ <div ref={ref} className={cn('space-y-2', className)} style={{ gap }}>
58
+ {Array.from({ length: lines }).map((_, i) => (
59
+ <Skeleton
60
+ key={i}
61
+ height={16}
62
+ width={i === lines - 1 ? '70%' : '100%'}
63
+ {...props}
64
+ />
65
+ ))}
66
+ </div>
67
+ )
68
+ }
69
+ )
70
+ SkeletonText.displayName = 'SkeletonText'
71
+
72
+ export interface SkeletonCardProps extends React.HTMLAttributes<HTMLDivElement> {
73
+ /** Whether to include a header */
74
+ hasHeader?: boolean
75
+ /** Whether to include an avatar/icon */
76
+ hasAvatar?: boolean
77
+ }
78
+
79
+ const SkeletonCard = React.forwardRef<HTMLDivElement, SkeletonCardProps>(
80
+ ({ hasHeader = true, hasAvatar = false, className, ...props }, ref) => {
81
+ return (
82
+ <div
83
+ ref={ref}
84
+ className={cn('rounded-lg border p-6 space-y-4', className)}
85
+ {...props}
86
+ >
87
+ {hasHeader && (
88
+ <div className="flex items-center gap-4">
89
+ {hasAvatar && <Skeleton variant="circular" width={40} height={40} />}
90
+ <div className="space-y-2 flex-1">
91
+ <Skeleton height={20} width="50%" />
92
+ <Skeleton height={14} width="30%" />
93
+ </div>
94
+ </div>
95
+ )}
96
+ <SkeletonText lines={3} />
97
+ </div>
98
+ )
99
+ }
100
+ )
101
+ SkeletonCard.displayName = 'SkeletonCard'
102
+
103
+ export { Skeleton, SkeletonText, SkeletonCard }
@@ -0,0 +1,205 @@
1
+ 'use client'
2
+
3
+ import * as React from 'react'
4
+ import { Check } from '@phosphor-icons/react'
5
+ import { cn } from '../lib/utils'
6
+
7
+ export interface Step {
8
+ id: number
9
+ label: string
10
+ description?: string
11
+ }
12
+
13
+ export interface StepProgressProps {
14
+ steps: Step[]
15
+ currentStep: number
16
+ onStepClick?: (step: number) => void
17
+ /** Orientation of the stepper */
18
+ orientation?: 'horizontal' | 'vertical'
19
+ /** Size variant */
20
+ size?: 'sm' | 'default' | 'lg'
21
+ /** Whether to show labels */
22
+ showLabels?: boolean
23
+ className?: string
24
+ }
25
+
26
+ const StepProgress = React.forwardRef<HTMLDivElement, StepProgressProps>(
27
+ (
28
+ {
29
+ steps,
30
+ currentStep,
31
+ onStepClick,
32
+ orientation = 'horizontal',
33
+ size = 'default',
34
+ showLabels = true,
35
+ className,
36
+ },
37
+ ref
38
+ ) => {
39
+ const sizeStyles = {
40
+ sm: {
41
+ indicator: 'w-6 h-6 text-xs',
42
+ icon: 12,
43
+ label: 'text-xs',
44
+ connector: orientation === 'horizontal' ? 'h-0.5' : 'w-0.5',
45
+ connectorLength: orientation === 'horizontal' ? 'w-4 sm:w-8' : 'h-6',
46
+ },
47
+ default: {
48
+ indicator: 'w-7 h-7 text-xs',
49
+ icon: 14,
50
+ label: 'text-sm',
51
+ connector: orientation === 'horizontal' ? 'h-0.5' : 'w-0.5',
52
+ connectorLength: orientation === 'horizontal' ? 'w-6 sm:w-10 md:w-14' : 'h-8',
53
+ },
54
+ lg: {
55
+ indicator: 'w-8 h-8 text-sm',
56
+ icon: 16,
57
+ label: 'text-sm',
58
+ connector: orientation === 'horizontal' ? 'h-0.5' : 'w-0.5',
59
+ connectorLength: orientation === 'horizontal' ? 'w-8 sm:w-12 md:w-16' : 'h-10',
60
+ },
61
+ }
62
+
63
+ const styles = sizeStyles[size]
64
+
65
+ return (
66
+ <div
67
+ ref={ref}
68
+ className={cn(
69
+ 'flex',
70
+ orientation === 'horizontal' ? 'flex-row items-center' : 'flex-col',
71
+ className
72
+ )}
73
+ >
74
+ {steps.map((step, index) => {
75
+ const isCompleted = step.id < currentStep
76
+ const isCurrent = step.id === currentStep
77
+ const isClickable = onStepClick && step.id < currentStep
78
+
79
+ return (
80
+ <div
81
+ key={step.id}
82
+ className={cn(
83
+ 'flex',
84
+ orientation === 'horizontal' ? 'flex-row items-center' : 'flex-col items-start'
85
+ )}
86
+ >
87
+ {/* Step */}
88
+ <button
89
+ type="button"
90
+ onClick={() => isClickable && onStepClick(step.id)}
91
+ disabled={!isClickable}
92
+ className={cn(
93
+ 'flex items-center gap-2 px-2 py-1.5 rounded-sm transition-colors',
94
+ isClickable ? 'cursor-pointer hover:bg-gray-50' : 'cursor-default',
95
+ orientation === 'vertical' && 'flex-row'
96
+ )}
97
+ >
98
+ {/* Number/Check indicator */}
99
+ <span
100
+ className={cn(
101
+ 'rounded-sm flex items-center justify-center font-bold transition-colors',
102
+ styles.indicator,
103
+ isCompleted
104
+ ? 'bg-[var(--cyan)] text-white'
105
+ : isCurrent
106
+ ? 'bg-[var(--black)] text-white'
107
+ : 'bg-gray-100 text-gray-400'
108
+ )}
109
+ >
110
+ {isCompleted ? (
111
+ <Check size={styles.icon} weight="bold" />
112
+ ) : (
113
+ step.id
114
+ )}
115
+ </span>
116
+
117
+ {/* Label */}
118
+ {showLabels && (
119
+ <div className={cn(
120
+ orientation === 'horizontal' && 'hidden sm:block',
121
+ 'text-left'
122
+ )}>
123
+ <span
124
+ className={cn(
125
+ 'font-medium transition-colors whitespace-nowrap',
126
+ styles.label,
127
+ isCompleted
128
+ ? 'text-[var(--cyan)]'
129
+ : isCurrent
130
+ ? 'text-[var(--black)]'
131
+ : 'text-gray-400'
132
+ )}
133
+ >
134
+ {step.label}
135
+ </span>
136
+ {step.description && orientation === 'vertical' && (
137
+ <p className="text-xs text-muted-foreground mt-0.5">
138
+ {step.description}
139
+ </p>
140
+ )}
141
+ </div>
142
+ )}
143
+ </button>
144
+
145
+ {/* Connector line */}
146
+ {index < steps.length - 1 && (
147
+ <div
148
+ className={cn(
149
+ 'transition-colors',
150
+ styles.connector,
151
+ styles.connectorLength,
152
+ isCompleted ? 'bg-[var(--cyan)]' : 'bg-gray-200',
153
+ orientation === 'vertical' && 'ml-[13px] my-1'
154
+ )}
155
+ />
156
+ )}
157
+ </div>
158
+ )
159
+ })}
160
+ </div>
161
+ )
162
+ }
163
+ )
164
+ StepProgress.displayName = 'StepProgress'
165
+
166
+ // Compact variant - just dots
167
+ export interface StepDotsProps {
168
+ totalSteps: number
169
+ currentStep: number
170
+ onStepClick?: (step: number) => void
171
+ className?: string
172
+ }
173
+
174
+ const StepDots = React.forwardRef<HTMLDivElement, StepDotsProps>(
175
+ ({ totalSteps, currentStep, onStepClick, className }, ref) => {
176
+ return (
177
+ <div ref={ref} className={cn('flex items-center gap-2', className)}>
178
+ {Array.from({ length: totalSteps }, (_, i) => i + 1).map((step) => {
179
+ const isCompleted = step < currentStep
180
+ const isCurrent = step === currentStep
181
+ const isClickable = onStepClick && step < currentStep
182
+
183
+ return (
184
+ <button
185
+ key={step}
186
+ type="button"
187
+ onClick={() => isClickable && onStepClick(step)}
188
+ disabled={!isClickable}
189
+ className={cn(
190
+ 'w-2 h-2 rounded-full transition-colors',
191
+ isClickable && 'cursor-pointer',
192
+ !isClickable && 'cursor-default',
193
+ isCompleted || isCurrent ? 'bg-[var(--cyan)]' : 'bg-gray-200'
194
+ )}
195
+ aria-label={`Step ${step}`}
196
+ />
197
+ )
198
+ })}
199
+ </div>
200
+ )
201
+ }
202
+ )
203
+ StepDots.displayName = 'StepDots'
204
+
205
+ export { StepProgress, StepDots }
@@ -0,0 +1,95 @@
1
+ 'use client'
2
+
3
+ import * as React from 'react'
4
+ import * as SwitchPrimitive from '@radix-ui/react-switch'
5
+ import { cn } from '../lib/utils'
6
+
7
+ export interface SwitchProps
8
+ extends React.ComponentPropsWithoutRef<typeof SwitchPrimitive.Root> {
9
+ /** Size variant */
10
+ size?: 'sm' | 'default' | 'lg'
11
+ }
12
+
13
+ const Switch = React.forwardRef<
14
+ React.ElementRef<typeof SwitchPrimitive.Root>,
15
+ SwitchProps
16
+ >(({ className, size = 'default', ...props }, ref) => {
17
+ const sizeStyles = {
18
+ sm: {
19
+ root: 'h-4 w-7',
20
+ thumb: 'h-3 w-3 data-[state=checked]:translate-x-3',
21
+ },
22
+ default: {
23
+ root: 'h-5 w-9',
24
+ thumb: 'h-4 w-4 data-[state=checked]:translate-x-4',
25
+ },
26
+ lg: {
27
+ root: 'h-6 w-11',
28
+ thumb: 'h-5 w-5 data-[state=checked]:translate-x-5',
29
+ },
30
+ }
31
+
32
+ return (
33
+ <SwitchPrimitive.Root
34
+ className={cn(
35
+ 'peer inline-flex shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-[var(--cyan)] data-[state=unchecked]:bg-input',
36
+ sizeStyles[size].root,
37
+ className
38
+ )}
39
+ {...props}
40
+ ref={ref}
41
+ >
42
+ <SwitchPrimitive.Thumb
43
+ className={cn(
44
+ 'pointer-events-none block rounded-full bg-white shadow-lg ring-0 transition-transform data-[state=unchecked]:translate-x-0',
45
+ sizeStyles[size].thumb
46
+ )}
47
+ />
48
+ </SwitchPrimitive.Root>
49
+ )
50
+ })
51
+ Switch.displayName = SwitchPrimitive.Root.displayName
52
+
53
+ // Convenience component with label
54
+ export interface LabeledSwitchProps extends SwitchProps {
55
+ label: string
56
+ description?: string
57
+ labelPosition?: 'left' | 'right'
58
+ }
59
+
60
+ const LabeledSwitch = React.forwardRef<
61
+ React.ElementRef<typeof SwitchPrimitive.Root>,
62
+ LabeledSwitchProps
63
+ >(({ label, description, labelPosition = 'right', className, id, ...props }, ref) => {
64
+ const switchId = id || React.useId()
65
+
66
+ const labelContent = (
67
+ <div className="space-y-0.5">
68
+ <label
69
+ htmlFor={switchId}
70
+ className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 cursor-pointer"
71
+ >
72
+ {label}
73
+ </label>
74
+ {description && (
75
+ <p className="text-xs text-muted-foreground">{description}</p>
76
+ )}
77
+ </div>
78
+ )
79
+
80
+ return (
81
+ <div
82
+ className={cn(
83
+ 'flex items-center gap-3',
84
+ labelPosition === 'left' && 'flex-row-reverse justify-end',
85
+ className
86
+ )}
87
+ >
88
+ <Switch ref={ref} id={switchId} {...props} />
89
+ {labelContent}
90
+ </div>
91
+ )
92
+ })
93
+ LabeledSwitch.displayName = 'LabeledSwitch'
94
+
95
+ export { Switch, LabeledSwitch }
@@ -0,0 +1,92 @@
1
+ 'use client'
2
+
3
+ import * as React from 'react'
4
+ import * as TabsPrimitive from '@radix-ui/react-tabs'
5
+ import { cn } from '../lib/utils'
6
+
7
+ const Tabs = TabsPrimitive.Root
8
+
9
+ const TabsList = React.forwardRef<
10
+ React.ElementRef<typeof TabsPrimitive.List>,
11
+ React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>
12
+ >(({ className, ...props }, ref) => (
13
+ <TabsPrimitive.List
14
+ ref={ref}
15
+ className={cn(
16
+ 'inline-flex h-10 items-center justify-center rounded-sm bg-muted p-1 text-muted-foreground',
17
+ className
18
+ )}
19
+ {...props}
20
+ />
21
+ ))
22
+ TabsList.displayName = TabsPrimitive.List.displayName
23
+
24
+ const TabsTrigger = React.forwardRef<
25
+ React.ElementRef<typeof TabsPrimitive.Trigger>,
26
+ React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>
27
+ >(({ className, ...props }, ref) => (
28
+ <TabsPrimitive.Trigger
29
+ ref={ref}
30
+ className={cn(
31
+ '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',
32
+ className
33
+ )}
34
+ {...props}
35
+ />
36
+ ))
37
+ TabsTrigger.displayName = TabsPrimitive.Trigger.displayName
38
+
39
+ const TabsContent = React.forwardRef<
40
+ React.ElementRef<typeof TabsPrimitive.Content>,
41
+ React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>
42
+ >(({ className, ...props }, ref) => (
43
+ <TabsPrimitive.Content
44
+ ref={ref}
45
+ className={cn(
46
+ 'mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',
47
+ className
48
+ )}
49
+ {...props}
50
+ />
51
+ ))
52
+ TabsContent.displayName = TabsPrimitive.Content.displayName
53
+
54
+ // Underline variant tabs
55
+ const TabsListUnderline = React.forwardRef<
56
+ React.ElementRef<typeof TabsPrimitive.List>,
57
+ React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>
58
+ >(({ className, ...props }, ref) => (
59
+ <TabsPrimitive.List
60
+ ref={ref}
61
+ className={cn(
62
+ 'inline-flex items-center justify-start border-b border-border',
63
+ className
64
+ )}
65
+ {...props}
66
+ />
67
+ ))
68
+ TabsListUnderline.displayName = 'TabsListUnderline'
69
+
70
+ const TabsTriggerUnderline = React.forwardRef<
71
+ React.ElementRef<typeof TabsPrimitive.Trigger>,
72
+ React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>
73
+ >(({ className, ...props }, ref) => (
74
+ <TabsPrimitive.Trigger
75
+ ref={ref}
76
+ className={cn(
77
+ 'inline-flex items-center justify-center whitespace-nowrap px-4 py-2 text-sm font-medium text-muted-foreground transition-colors hover:text-foreground border-b-2 border-transparent -mb-px data-[state=active]:text-foreground data-[state=active]:border-[var(--cyan)] disabled:pointer-events-none disabled:opacity-50',
78
+ className
79
+ )}
80
+ {...props}
81
+ />
82
+ ))
83
+ TabsTriggerUnderline.displayName = 'TabsTriggerUnderline'
84
+
85
+ export {
86
+ Tabs,
87
+ TabsList,
88
+ TabsTrigger,
89
+ TabsContent,
90
+ TabsListUnderline,
91
+ TabsTriggerUnderline,
92
+ }
@@ -32,6 +32,7 @@ const toastVariants = cva(
32
32
  success: 'bg-[var(--black)] text-white',
33
33
  error: 'bg-[var(--black)] text-white',
34
34
  warning: 'bg-[var(--black)] text-white',
35
+ info: 'bg-[var(--black)] text-white',
35
36
  },
36
37
  },
37
38
  defaultVariants: {
@@ -117,7 +118,7 @@ type ToastProps = React.ComponentPropsWithoutRef<typeof Toast>
117
118
  type ToastActionElement = React.ReactElement<typeof ToastAction>
118
119
 
119
120
  // Toast icon helper
120
- const ToastIcon = ({ variant }: { variant?: 'default' | 'success' | 'error' | 'warning' }) => {
121
+ const ToastIcon = ({ variant }: { variant?: 'default' | 'success' | 'error' | 'warning' | 'info' }) => {
121
122
  switch (variant) {
122
123
  case 'success':
123
124
  return <Check size={18} weight="bold" className="text-[var(--cyan)]" />
@@ -125,6 +126,8 @@ const ToastIcon = ({ variant }: { variant?: 'default' | 'success' | 'error' | 'w
125
126
  return <WarningCircle size={18} weight="fill" className="text-red-400" />
126
127
  case 'warning':
127
128
  return <WarningCircle size={18} weight="fill" className="text-amber-400" />
129
+ case 'info':
130
+ return <Info size={18} weight="fill" className="text-[var(--cyan)]" />
128
131
  default:
129
132
  return <Info size={18} weight="fill" className="text-white/70" />
130
133
  }
@@ -0,0 +1,78 @@
1
+ 'use client'
2
+
3
+ import * as React from 'react'
4
+ import * as TooltipPrimitive from '@radix-ui/react-tooltip'
5
+ import { cn } from '../lib/utils'
6
+
7
+ const TooltipProvider = TooltipPrimitive.Provider
8
+
9
+ const Tooltip = TooltipPrimitive.Root
10
+
11
+ const TooltipTrigger = TooltipPrimitive.Trigger
12
+
13
+ const TooltipContent = React.forwardRef<
14
+ React.ElementRef<typeof TooltipPrimitive.Content>,
15
+ React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
16
+ >(({ className, sideOffset = 4, ...props }, ref) => (
17
+ <TooltipPrimitive.Portal>
18
+ <TooltipPrimitive.Content
19
+ ref={ref}
20
+ sideOffset={sideOffset}
21
+ className={cn(
22
+ 'z-50 overflow-hidden rounded-sm bg-[var(--black)] px-3 py-1.5 text-xs text-white 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',
23
+ className
24
+ )}
25
+ {...props}
26
+ />
27
+ </TooltipPrimitive.Portal>
28
+ ))
29
+ TooltipContent.displayName = TooltipPrimitive.Content.displayName
30
+
31
+ const TooltipArrow = React.forwardRef<
32
+ React.ElementRef<typeof TooltipPrimitive.Arrow>,
33
+ React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Arrow>
34
+ >(({ className, ...props }, ref) => (
35
+ <TooltipPrimitive.Arrow
36
+ ref={ref}
37
+ className={cn('fill-[var(--black)]', className)}
38
+ {...props}
39
+ />
40
+ ))
41
+ TooltipArrow.displayName = TooltipPrimitive.Arrow.displayName
42
+
43
+ // Convenience component for simple tooltips
44
+ export interface SimpleTooltipProps {
45
+ content: React.ReactNode
46
+ children: React.ReactNode
47
+ side?: 'top' | 'right' | 'bottom' | 'left'
48
+ align?: 'start' | 'center' | 'end'
49
+ delayDuration?: number
50
+ }
51
+
52
+ function SimpleTooltip({
53
+ content,
54
+ children,
55
+ side = 'top',
56
+ align = 'center',
57
+ delayDuration = 200,
58
+ }: SimpleTooltipProps) {
59
+ return (
60
+ <TooltipProvider delayDuration={delayDuration}>
61
+ <Tooltip>
62
+ <TooltipTrigger asChild>{children}</TooltipTrigger>
63
+ <TooltipContent side={side} align={align}>
64
+ {content}
65
+ </TooltipContent>
66
+ </Tooltip>
67
+ </TooltipProvider>
68
+ )
69
+ }
70
+
71
+ export {
72
+ Tooltip,
73
+ TooltipTrigger,
74
+ TooltipContent,
75
+ TooltipProvider,
76
+ TooltipArrow,
77
+ SimpleTooltip,
78
+ }