@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.
- package/dist/components/alert-dialog.d.ts +34 -0
- package/dist/components/alert-dialog.d.ts.map +1 -0
- package/dist/components/breadcrumbs.d.ts +30 -0
- package/dist/components/breadcrumbs.d.ts.map +1 -0
- package/dist/components/date-range-picker.d.ts +36 -0
- package/dist/components/date-range-picker.d.ts.map +1 -0
- package/dist/components/pagination.d.ts +29 -0
- package/dist/components/pagination.d.ts.map +1 -0
- package/dist/components/popover.d.ts +10 -0
- package/dist/components/popover.d.ts.map +1 -0
- package/dist/components/radio-group.d.ts +17 -0
- package/dist/components/radio-group.d.ts.map +1 -0
- package/dist/components/select.d.ts.map +1 -1
- package/dist/components/settings-nav.d.ts +35 -0
- package/dist/components/settings-nav.d.ts.map +1 -0
- package/dist/components/skeleton.d.ts +28 -0
- package/dist/components/skeleton.d.ts.map +1 -0
- package/dist/components/step-progress.d.ts +28 -0
- package/dist/components/step-progress.d.ts.map +1 -0
- package/dist/components/switch.d.ts +15 -0
- package/dist/components/switch.d.ts.map +1 -0
- package/dist/components/tabs.d.ts +10 -0
- package/dist/components/tabs.d.ts.map +1 -0
- package/dist/components/toast.d.ts +2 -2
- package/dist/components/toast.d.ts.map +1 -1
- package/dist/components/tooltip.d.ts +17 -0
- package/dist/components/tooltip.d.ts.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1273 -93
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1219 -95
- package/dist/index.mjs.map +1 -1
- package/package.json +10 -2
- package/src/components/alert-dialog.tsx +203 -0
- package/src/components/breadcrumbs.tsx +160 -0
- package/src/components/date-range-picker.tsx +183 -0
- package/src/components/dialog.stories.tsx +91 -0
- package/src/components/dialog.tsx +2 -2
- package/src/components/dropdown-menu.stories.tsx +102 -0
- package/src/components/dropdown-menu.tsx +2 -2
- package/src/components/pagination.tsx +220 -0
- package/src/components/popover.tsx +53 -0
- package/src/components/radio-group.tsx +125 -0
- package/src/components/select.tsx +2 -1
- package/src/components/settings-nav.tsx +137 -0
- package/src/components/skeleton.tsx +103 -0
- package/src/components/step-progress.tsx +205 -0
- package/src/components/switch.tsx +95 -0
- package/src/components/tabs.tsx +92 -0
- package/src/components/toast.tsx +4 -1
- package/src/components/tooltip.tsx +78 -0
- package/src/index.ts +78 -0
- 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
|
+
}
|
package/src/components/toast.tsx
CHANGED
|
@@ -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
|
+
}
|