@dilipod/ui 0.2.4 → 0.2.5
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/accordion.d.ts +8 -0
- package/dist/components/accordion.d.ts.map +1 -0
- package/dist/components/alert.d.ts +16 -0
- package/dist/components/alert.d.ts.map +1 -0
- package/dist/components/avatar.d.ts +7 -0
- package/dist/components/avatar.d.ts.map +1 -0
- package/dist/components/badge.d.ts +15 -0
- package/dist/components/badge.d.ts.map +1 -0
- package/dist/components/button.d.ts +16 -0
- package/dist/components/button.d.ts.map +1 -0
- package/dist/components/card.d.ts +9 -0
- package/dist/components/card.d.ts.map +1 -0
- package/dist/components/checkbox.d.ts +7 -0
- package/dist/components/checkbox.d.ts.map +1 -0
- package/dist/components/code-block.d.ts +10 -0
- package/dist/components/code-block.d.ts.map +1 -0
- package/dist/components/divider.d.ts +10 -0
- package/dist/components/divider.d.ts.map +1 -0
- package/dist/components/dropdown-menu.d.ts +28 -0
- package/dist/components/dropdown-menu.d.ts.map +1 -0
- package/dist/components/empty-state.d.ts +16 -0
- package/dist/components/empty-state.d.ts.map +1 -0
- package/dist/components/form-field.d.ts +20 -0
- package/dist/components/form-field.d.ts.map +1 -0
- package/dist/components/icon-box.d.ts +12 -0
- package/dist/components/icon-box.d.ts.map +1 -0
- package/dist/components/input.d.ts +8 -0
- package/dist/components/input.d.ts.map +1 -0
- package/dist/components/label.d.ts +7 -0
- package/dist/components/label.d.ts.map +1 -0
- package/dist/components/logo.d.ts +17 -0
- package/dist/components/logo.d.ts.map +1 -0
- package/dist/components/navigation-menu.d.ts +13 -0
- package/dist/components/navigation-menu.d.ts.map +1 -0
- package/dist/components/progress.d.ts +18 -0
- package/dist/components/progress.d.ts.map +1 -0
- package/dist/components/separator.d.ts +6 -0
- package/dist/components/separator.d.ts.map +1 -0
- package/dist/components/sheet.d.ts +26 -0
- package/dist/components/sheet.d.ts.map +1 -0
- package/dist/components/sidebar.d.ts +51 -0
- package/dist/components/sidebar.d.ts.map +1 -0
- package/dist/components/stat.d.ts +25 -0
- package/dist/components/stat.d.ts.map +1 -0
- package/dist/components/table.d.ts +11 -0
- package/dist/components/table.d.ts.map +1 -0
- package/dist/components/tag.d.ts +13 -0
- package/dist/components/tag.d.ts.map +1 -0
- package/dist/components/textarea.d.ts +8 -0
- package/dist/components/textarea.d.ts.map +1 -0
- package/dist/icons.d.ts +17 -0
- package/dist/icons.d.ts.map +1 -0
- package/dist/index.d.ts +46 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +278 -10
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +266 -12
- package/dist/index.mjs.map +1 -1
- package/dist/lib/utils.d.ts +3 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/package.json +2 -2
- package/src/components/alert.tsx +67 -0
- package/src/components/button.tsx +33 -2
- package/src/components/code-block.tsx +32 -0
- package/src/components/divider.tsx +52 -0
- package/src/components/dropdown-menu.tsx +3 -3
- package/src/components/empty-state.tsx +63 -0
- package/src/components/form-field.tsx +73 -0
- package/src/components/input.tsx +10 -3
- package/src/components/sidebar.tsx +4 -4
- package/src/components/table.tsx +108 -0
- package/src/components/textarea.tsx +10 -3
- package/src/index.ts +26 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
import { cva, type VariantProps } from 'class-variance-authority'
|
|
5
|
+
import { cn } from '../lib/utils'
|
|
6
|
+
|
|
7
|
+
const alertVariants = cva(
|
|
8
|
+
'rounded-sm border p-3 text-sm',
|
|
9
|
+
{
|
|
10
|
+
variants: {
|
|
11
|
+
variant: {
|
|
12
|
+
default: 'bg-background border-border text-foreground',
|
|
13
|
+
success: 'bg-green-50 border-green-200 text-green-900',
|
|
14
|
+
error: 'bg-red-50 border-red-200 text-red-900',
|
|
15
|
+
warning: 'bg-amber-50 border-amber-200 text-amber-900',
|
|
16
|
+
info: 'bg-blue-50 border-blue-200 text-blue-900',
|
|
17
|
+
primary: 'bg-[var(--cyan)]/10 border-[var(--cyan)]/20 text-[var(--cyan)]',
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
defaultVariants: {
|
|
21
|
+
variant: 'default',
|
|
22
|
+
},
|
|
23
|
+
}
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
export interface AlertProps
|
|
27
|
+
extends React.HTMLAttributes<HTMLDivElement>,
|
|
28
|
+
VariantProps<typeof alertVariants> {
|
|
29
|
+
/** Optional icon to display */
|
|
30
|
+
icon?: React.ReactNode
|
|
31
|
+
/** Optional title */
|
|
32
|
+
title?: string
|
|
33
|
+
/** Optional action button */
|
|
34
|
+
action?: React.ReactNode
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const Alert = React.forwardRef<HTMLDivElement, AlertProps>(
|
|
38
|
+
({ className, variant, icon, title, action, children, ...props }, ref) => {
|
|
39
|
+
return (
|
|
40
|
+
<div
|
|
41
|
+
ref={ref}
|
|
42
|
+
className={cn(alertVariants({ variant }), className)}
|
|
43
|
+
{...props}
|
|
44
|
+
>
|
|
45
|
+
<div className="flex items-start justify-between gap-3">
|
|
46
|
+
<div className="flex items-start gap-3 flex-1">
|
|
47
|
+
{icon && <div className="shrink-0 mt-0.5">{icon}</div>}
|
|
48
|
+
<div className="flex-1 min-w-0">
|
|
49
|
+
{title && (
|
|
50
|
+
<p className="font-semibold mb-1">{title}</p>
|
|
51
|
+
)}
|
|
52
|
+
<div className={title ? 'text-sm' : ''}>{children}</div>
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
{action && (
|
|
56
|
+
<div className="shrink-0">
|
|
57
|
+
{action}
|
|
58
|
+
</div>
|
|
59
|
+
)}
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
)
|
|
63
|
+
}
|
|
64
|
+
)
|
|
65
|
+
Alert.displayName = 'Alert'
|
|
66
|
+
|
|
67
|
+
export { Alert, alertVariants }
|
|
@@ -44,17 +44,48 @@ export interface ButtonProps
|
|
|
44
44
|
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
|
45
45
|
VariantProps<typeof buttonVariants> {
|
|
46
46
|
asChild?: boolean
|
|
47
|
+
/** Show loading state */
|
|
48
|
+
loading?: boolean
|
|
49
|
+
/** Loading text (defaults to current children text) */
|
|
50
|
+
loadingText?: string
|
|
47
51
|
}
|
|
48
52
|
|
|
49
53
|
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
|
50
|
-
({ className, variant, size, asChild = false, ...props }, ref) => {
|
|
54
|
+
({ className, variant, size, asChild = false, loading, loadingText, children, disabled, ...props }, ref) => {
|
|
51
55
|
const Comp = asChild ? Slot : 'button'
|
|
56
|
+
const isDisabled = disabled || loading
|
|
57
|
+
|
|
52
58
|
return (
|
|
53
59
|
<Comp
|
|
54
60
|
className={cn(buttonVariants({ variant, size, className }))}
|
|
55
61
|
ref={ref}
|
|
62
|
+
disabled={isDisabled}
|
|
56
63
|
{...props}
|
|
57
|
-
|
|
64
|
+
>
|
|
65
|
+
{loading && (
|
|
66
|
+
<svg
|
|
67
|
+
className="animate-spin h-4 w-4"
|
|
68
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
69
|
+
fill="none"
|
|
70
|
+
viewBox="0 0 24 24"
|
|
71
|
+
>
|
|
72
|
+
<circle
|
|
73
|
+
className="opacity-25"
|
|
74
|
+
cx="12"
|
|
75
|
+
cy="12"
|
|
76
|
+
r="10"
|
|
77
|
+
stroke="currentColor"
|
|
78
|
+
strokeWidth="4"
|
|
79
|
+
/>
|
|
80
|
+
<path
|
|
81
|
+
className="opacity-75"
|
|
82
|
+
fill="currentColor"
|
|
83
|
+
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
|
84
|
+
/>
|
|
85
|
+
</svg>
|
|
86
|
+
)}
|
|
87
|
+
{loading ? loadingText || children : children}
|
|
88
|
+
</Comp>
|
|
58
89
|
)
|
|
59
90
|
}
|
|
60
91
|
)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
import { cn } from '../lib/utils'
|
|
5
|
+
|
|
6
|
+
export interface CodeBlockProps extends React.HTMLAttributes<HTMLPreElement> {
|
|
7
|
+
/** Code content */
|
|
8
|
+
children?: React.ReactNode
|
|
9
|
+
/** Language for syntax highlighting (optional) */
|
|
10
|
+
language?: string
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const CodeBlock = React.forwardRef<HTMLPreElement, CodeBlockProps>(
|
|
14
|
+
({ className, children, language, ...props }, ref) => {
|
|
15
|
+
return (
|
|
16
|
+
<pre
|
|
17
|
+
ref={ref}
|
|
18
|
+
className={cn(
|
|
19
|
+
'rounded-sm bg-muted p-4 text-sm overflow-auto font-mono',
|
|
20
|
+
className
|
|
21
|
+
)}
|
|
22
|
+
{...(language && { 'data-language': language })}
|
|
23
|
+
{...props}
|
|
24
|
+
>
|
|
25
|
+
<code>{children}</code>
|
|
26
|
+
</pre>
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
)
|
|
30
|
+
CodeBlock.displayName = 'CodeBlock'
|
|
31
|
+
|
|
32
|
+
export { CodeBlock }
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
import { cn } from '../lib/utils'
|
|
5
|
+
|
|
6
|
+
export interface DividerProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
7
|
+
/** Text to display in the divider */
|
|
8
|
+
text?: string
|
|
9
|
+
/** Orientation */
|
|
10
|
+
orientation?: 'horizontal' | 'vertical'
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const Divider = React.forwardRef<HTMLDivElement, DividerProps>(
|
|
14
|
+
({ className, text, orientation = 'horizontal', ...props }, ref) => {
|
|
15
|
+
if (orientation === 'vertical') {
|
|
16
|
+
return (
|
|
17
|
+
<div
|
|
18
|
+
ref={ref}
|
|
19
|
+
className={cn('w-px h-full bg-border', className)}
|
|
20
|
+
{...props}
|
|
21
|
+
/>
|
|
22
|
+
)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (text) {
|
|
26
|
+
return (
|
|
27
|
+
<div
|
|
28
|
+
ref={ref}
|
|
29
|
+
className={cn('relative flex items-center', className)}
|
|
30
|
+
{...props}
|
|
31
|
+
>
|
|
32
|
+
<div className="flex-1 border-t" />
|
|
33
|
+
<span className="px-2 text-xs uppercase text-muted-foreground bg-background">
|
|
34
|
+
{text}
|
|
35
|
+
</span>
|
|
36
|
+
<div className="flex-1 border-t" />
|
|
37
|
+
</div>
|
|
38
|
+
)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<div
|
|
43
|
+
ref={ref}
|
|
44
|
+
className={cn('border-t', className)}
|
|
45
|
+
{...props}
|
|
46
|
+
/>
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
)
|
|
50
|
+
Divider.displayName = 'Divider'
|
|
51
|
+
|
|
52
|
+
export { Divider }
|
|
@@ -65,7 +65,7 @@ const DropdownMenuContent = React.forwardRef<
|
|
|
65
65
|
ref={ref}
|
|
66
66
|
sideOffset={sideOffset}
|
|
67
67
|
className={cn(
|
|
68
|
-
"z-50 max-h-[var(--radix-dropdown-menu-content-available-height)] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-sm border bg-popover p-1 text-popover-foreground shadow-md 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-[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 origin-[--radix-dropdown-menu-content-transform-origin]",
|
|
68
|
+
"z-50 max-h-[var(--radix-dropdown-menu-content-available-height)] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-sm border bg-popover p-1.5 text-popover-foreground shadow-md 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-[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 origin-[--radix-dropdown-menu-content-transform-origin]",
|
|
69
69
|
className
|
|
70
70
|
)}
|
|
71
71
|
{...props}
|
|
@@ -83,7 +83,7 @@ const DropdownMenuItem = React.forwardRef<
|
|
|
83
83
|
<DropdownMenuPrimitive.Item
|
|
84
84
|
ref={ref}
|
|
85
85
|
className={cn(
|
|
86
|
-
"relative flex cursor-
|
|
86
|
+
"relative flex cursor-pointer select-none items-center gap-2 rounded-sm px-3 py-2 text-sm outline-none transition-colors focus:bg-muted focus:text-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
|
87
87
|
inset && "pl-8",
|
|
88
88
|
className
|
|
89
89
|
)}
|
|
@@ -147,7 +147,7 @@ const DropdownMenuLabel = React.forwardRef<
|
|
|
147
147
|
<DropdownMenuPrimitive.Label
|
|
148
148
|
ref={ref}
|
|
149
149
|
className={cn(
|
|
150
|
-
"px-
|
|
150
|
+
"px-3 py-2 text-sm font-semibold text-foreground",
|
|
151
151
|
inset && "pl-8",
|
|
152
152
|
className
|
|
153
153
|
)}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
import { cn } from '../lib/utils'
|
|
5
|
+
|
|
6
|
+
export interface EmptyStateProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
7
|
+
/** Optional icon to display */
|
|
8
|
+
icon?: React.ReactNode
|
|
9
|
+
/** Title text */
|
|
10
|
+
title?: string
|
|
11
|
+
/** Description text */
|
|
12
|
+
description?: string
|
|
13
|
+
/** Optional action button */
|
|
14
|
+
action?: React.ReactNode
|
|
15
|
+
/** Size variant */
|
|
16
|
+
size?: 'sm' | 'default' | 'lg'
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const EmptyState = React.forwardRef<HTMLDivElement, EmptyStateProps>(
|
|
20
|
+
({ className, icon, title, description, action, size = 'default', ...props }, ref) => {
|
|
21
|
+
const paddingClass = {
|
|
22
|
+
sm: 'p-8',
|
|
23
|
+
default: 'p-12',
|
|
24
|
+
lg: 'p-16',
|
|
25
|
+
}[size]
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<div
|
|
29
|
+
ref={ref}
|
|
30
|
+
className={cn(
|
|
31
|
+
'rounded-sm border border-dashed text-center',
|
|
32
|
+
paddingClass,
|
|
33
|
+
className
|
|
34
|
+
)}
|
|
35
|
+
{...props}
|
|
36
|
+
>
|
|
37
|
+
{icon && (
|
|
38
|
+
<div className="flex justify-center mb-4">
|
|
39
|
+
{icon}
|
|
40
|
+
</div>
|
|
41
|
+
)}
|
|
42
|
+
{title && (
|
|
43
|
+
<h3 className="text-sm font-semibold text-foreground mb-1">
|
|
44
|
+
{title}
|
|
45
|
+
</h3>
|
|
46
|
+
)}
|
|
47
|
+
{description && (
|
|
48
|
+
<p className="text-sm text-muted-foreground mb-4">
|
|
49
|
+
{description}
|
|
50
|
+
</p>
|
|
51
|
+
)}
|
|
52
|
+
{action && (
|
|
53
|
+
<div className="flex justify-center">
|
|
54
|
+
{action}
|
|
55
|
+
</div>
|
|
56
|
+
)}
|
|
57
|
+
</div>
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
)
|
|
61
|
+
EmptyState.displayName = 'EmptyState'
|
|
62
|
+
|
|
63
|
+
export { EmptyState }
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
import { cn } from '../lib/utils'
|
|
5
|
+
import { Label } from './label'
|
|
6
|
+
import { Input } from './input'
|
|
7
|
+
import { Textarea } from './textarea'
|
|
8
|
+
|
|
9
|
+
export interface FormFieldProps {
|
|
10
|
+
/** Field label */
|
|
11
|
+
label?: string
|
|
12
|
+
/** Error message to display */
|
|
13
|
+
error?: string
|
|
14
|
+
/** Helper text to display */
|
|
15
|
+
helperText?: string
|
|
16
|
+
/** Whether the field is required */
|
|
17
|
+
required?: boolean
|
|
18
|
+
/** Field ID for accessibility */
|
|
19
|
+
id?: string
|
|
20
|
+
/** Additional className */
|
|
21
|
+
className?: string
|
|
22
|
+
/** Field content (Input, Textarea, etc.) */
|
|
23
|
+
children: React.ReactNode
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const FormField = React.forwardRef<HTMLDivElement, FormFieldProps>(
|
|
27
|
+
({ label, error, helperText, required, id, className, children, ...props }, ref) => {
|
|
28
|
+
const fieldId = id || React.useId()
|
|
29
|
+
const errorId = `${fieldId}-error`
|
|
30
|
+
const helperId = `${fieldId}-helper`
|
|
31
|
+
|
|
32
|
+
// Clone children to add error state and IDs
|
|
33
|
+
const enhancedChildren = React.Children.map(children, (child) => {
|
|
34
|
+
if (React.isValidElement(child)) {
|
|
35
|
+
const childProps = child.props as { className?: string; [key: string]: any }
|
|
36
|
+
return React.cloneElement(child as React.ReactElement<any>, {
|
|
37
|
+
id: fieldId,
|
|
38
|
+
'aria-invalid': error ? 'true' : undefined,
|
|
39
|
+
'aria-describedby': error ? errorId : helperText ? helperId : undefined,
|
|
40
|
+
className: cn(
|
|
41
|
+
childProps.className,
|
|
42
|
+
error && 'border-red-500 focus-visible:ring-red-500'
|
|
43
|
+
),
|
|
44
|
+
})
|
|
45
|
+
}
|
|
46
|
+
return child
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<div ref={ref} className={cn('space-y-2', className)} {...props}>
|
|
51
|
+
{label && (
|
|
52
|
+
<Label htmlFor={fieldId} className={required ? 'after:content-["*"] after:ml-0.5 after:text-red-500' : ''}>
|
|
53
|
+
{label}
|
|
54
|
+
</Label>
|
|
55
|
+
)}
|
|
56
|
+
{enhancedChildren}
|
|
57
|
+
{error && (
|
|
58
|
+
<p id={errorId} className="text-sm text-red-600" role="alert">
|
|
59
|
+
{error}
|
|
60
|
+
</p>
|
|
61
|
+
)}
|
|
62
|
+
{helperText && !error && (
|
|
63
|
+
<p id={helperId} className="text-xs text-muted-foreground">
|
|
64
|
+
{helperText}
|
|
65
|
+
</p>
|
|
66
|
+
)}
|
|
67
|
+
</div>
|
|
68
|
+
)
|
|
69
|
+
}
|
|
70
|
+
)
|
|
71
|
+
FormField.displayName = 'FormField'
|
|
72
|
+
|
|
73
|
+
export { FormField }
|
package/src/components/input.tsx
CHANGED
|
@@ -4,18 +4,25 @@ import * as React from 'react'
|
|
|
4
4
|
import { cn } from '../lib/utils'
|
|
5
5
|
|
|
6
6
|
export interface InputProps
|
|
7
|
-
extends React.InputHTMLAttributes<HTMLInputElement> {
|
|
7
|
+
extends React.InputHTMLAttributes<HTMLInputElement> {
|
|
8
|
+
/** Show error state */
|
|
9
|
+
error?: boolean
|
|
10
|
+
}
|
|
8
11
|
|
|
9
12
|
const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|
10
|
-
({ className, type, ...props }, ref) => {
|
|
13
|
+
({ className, type, error, ...props }, ref) => {
|
|
11
14
|
return (
|
|
12
15
|
<input
|
|
13
16
|
type={type}
|
|
14
17
|
className={cn(
|
|
15
|
-
'flex h-10 w-full rounded-
|
|
18
|
+
'flex h-10 w-full rounded-sm border bg-white px-3 py-2 text-base text-[var(--black)] ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-[var(--black)] placeholder:text-gray-500 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm transition-colors',
|
|
19
|
+
error
|
|
20
|
+
? 'border-red-500 focus-visible:ring-red-500'
|
|
21
|
+
: 'border-gray-300 focus-visible:ring-[var(--cyan)]',
|
|
16
22
|
className
|
|
17
23
|
)}
|
|
18
24
|
ref={ref}
|
|
25
|
+
aria-invalid={error ? 'true' : undefined}
|
|
19
26
|
{...props}
|
|
20
27
|
/>
|
|
21
28
|
)
|
|
@@ -7,7 +7,7 @@ import type { Icon } from '../icons'
|
|
|
7
7
|
export interface SidebarNavItem {
|
|
8
8
|
name: string
|
|
9
9
|
href: string
|
|
10
|
-
icon:
|
|
10
|
+
icon: React.ComponentType<React.SVGProps<SVGSVGElement> & { weight?: 'fill' | 'regular' }>
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
export interface SidebarProps extends React.HTMLAttributes<HTMLElement> {
|
|
@@ -27,7 +27,7 @@ export interface SidebarProps extends React.HTMLAttributes<HTMLElement> {
|
|
|
27
27
|
helpLink?: {
|
|
28
28
|
href: string
|
|
29
29
|
label?: string
|
|
30
|
-
icon?:
|
|
30
|
+
icon?: React.ComponentType<React.SVGProps<SVGSVGElement> & { weight?: 'fill' | 'regular' }>
|
|
31
31
|
}
|
|
32
32
|
/** Header content (e.g., Logo) */
|
|
33
33
|
header?: React.ReactNode
|
|
@@ -43,9 +43,9 @@ export interface SidebarNavItemProps {
|
|
|
43
43
|
LinkComponent?: React.ComponentType<{ href: string; className?: string; children?: React.ReactNode } & Record<string, any>>
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
const SidebarNavItem = React.forwardRef<
|
|
46
|
+
const SidebarNavItem = React.forwardRef<HTMLAnchorElement, SidebarNavItemProps>(
|
|
47
47
|
({ item, isActive, className, LinkComponent, ...props }, ref) => {
|
|
48
|
-
const Icon = item.icon
|
|
48
|
+
const Icon = item.icon as React.ComponentType<any>
|
|
49
49
|
const baseClassName = cn(
|
|
50
50
|
'flex items-center gap-3 rounded-sm px-3 py-2 text-sm transition-colors',
|
|
51
51
|
isActive
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
import { cn } from '../lib/utils'
|
|
5
|
+
|
|
6
|
+
const Table = React.forwardRef<
|
|
7
|
+
HTMLTableElement,
|
|
8
|
+
React.HTMLAttributes<HTMLTableElement>
|
|
9
|
+
>(({ className, ...props }, ref) => (
|
|
10
|
+
<div className="overflow-x-auto">
|
|
11
|
+
<table
|
|
12
|
+
ref={ref}
|
|
13
|
+
className={cn('w-full border-collapse', className)}
|
|
14
|
+
{...props}
|
|
15
|
+
/>
|
|
16
|
+
</div>
|
|
17
|
+
))
|
|
18
|
+
Table.displayName = 'Table'
|
|
19
|
+
|
|
20
|
+
const TableHeader = React.forwardRef<
|
|
21
|
+
HTMLTableSectionElement,
|
|
22
|
+
React.HTMLAttributes<HTMLTableSectionElement>
|
|
23
|
+
>(({ className, ...props }, ref) => (
|
|
24
|
+
<thead ref={ref} className={cn('', className)} {...props} />
|
|
25
|
+
))
|
|
26
|
+
TableHeader.displayName = 'TableHeader'
|
|
27
|
+
|
|
28
|
+
const TableBody = React.forwardRef<
|
|
29
|
+
HTMLTableSectionElement,
|
|
30
|
+
React.HTMLAttributes<HTMLTableSectionElement>
|
|
31
|
+
>(({ className, ...props }, ref) => (
|
|
32
|
+
<tbody ref={ref} className={cn('', className)} {...props} />
|
|
33
|
+
))
|
|
34
|
+
TableBody.displayName = 'TableBody'
|
|
35
|
+
|
|
36
|
+
const TableFooter = React.forwardRef<
|
|
37
|
+
HTMLTableSectionElement,
|
|
38
|
+
React.HTMLAttributes<HTMLTableSectionElement>
|
|
39
|
+
>(({ className, ...props }, ref) => (
|
|
40
|
+
<tfoot
|
|
41
|
+
ref={ref}
|
|
42
|
+
className={cn('border-t bg-muted/50 font-medium', className)}
|
|
43
|
+
{...props}
|
|
44
|
+
/>
|
|
45
|
+
))
|
|
46
|
+
TableFooter.displayName = 'TableFooter'
|
|
47
|
+
|
|
48
|
+
const TableRow = React.forwardRef<
|
|
49
|
+
HTMLTableRowElement,
|
|
50
|
+
React.HTMLAttributes<HTMLTableRowElement>
|
|
51
|
+
>(({ className, ...props }, ref) => (
|
|
52
|
+
<tr
|
|
53
|
+
ref={ref}
|
|
54
|
+
className={cn('border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted', className)}
|
|
55
|
+
{...props}
|
|
56
|
+
/>
|
|
57
|
+
))
|
|
58
|
+
TableRow.displayName = 'TableRow'
|
|
59
|
+
|
|
60
|
+
const TableHead = React.forwardRef<
|
|
61
|
+
HTMLTableCellElement,
|
|
62
|
+
React.ThHTMLAttributes<HTMLTableCellElement>
|
|
63
|
+
>(({ className, ...props }, ref) => (
|
|
64
|
+
<th
|
|
65
|
+
ref={ref}
|
|
66
|
+
className={cn(
|
|
67
|
+
'h-12 px-4 text-left align-middle font-semibold text-muted-foreground [&:has([role=checkbox])]:pr-0',
|
|
68
|
+
className
|
|
69
|
+
)}
|
|
70
|
+
{...props}
|
|
71
|
+
/>
|
|
72
|
+
))
|
|
73
|
+
TableHead.displayName = 'TableHead'
|
|
74
|
+
|
|
75
|
+
const TableCell = React.forwardRef<
|
|
76
|
+
HTMLTableCellElement,
|
|
77
|
+
React.TdHTMLAttributes<HTMLTableCellElement>
|
|
78
|
+
>(({ className, ...props }, ref) => (
|
|
79
|
+
<td
|
|
80
|
+
ref={ref}
|
|
81
|
+
className={cn('p-4 align-middle [&:has([role=checkbox])]:pr-0', className)}
|
|
82
|
+
{...props}
|
|
83
|
+
/>
|
|
84
|
+
))
|
|
85
|
+
TableCell.displayName = 'TableCell'
|
|
86
|
+
|
|
87
|
+
const TableCaption = React.forwardRef<
|
|
88
|
+
HTMLTableCaptionElement,
|
|
89
|
+
React.HTMLAttributes<HTMLTableCaptionElement>
|
|
90
|
+
>(({ className, ...props }, ref) => (
|
|
91
|
+
<caption
|
|
92
|
+
ref={ref}
|
|
93
|
+
className={cn('mt-4 text-sm text-muted-foreground', className)}
|
|
94
|
+
{...props}
|
|
95
|
+
/>
|
|
96
|
+
))
|
|
97
|
+
TableCaption.displayName = 'TableCaption'
|
|
98
|
+
|
|
99
|
+
export {
|
|
100
|
+
Table,
|
|
101
|
+
TableHeader,
|
|
102
|
+
TableBody,
|
|
103
|
+
TableFooter,
|
|
104
|
+
TableHead,
|
|
105
|
+
TableRow,
|
|
106
|
+
TableCell,
|
|
107
|
+
TableCaption,
|
|
108
|
+
}
|
|
@@ -4,17 +4,24 @@ import * as React from 'react'
|
|
|
4
4
|
import { cn } from '../lib/utils'
|
|
5
5
|
|
|
6
6
|
export interface TextareaProps
|
|
7
|
-
extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {
|
|
7
|
+
extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {
|
|
8
|
+
/** Show error state */
|
|
9
|
+
error?: boolean
|
|
10
|
+
}
|
|
8
11
|
|
|
9
12
|
const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
|
|
10
|
-
({ className, ...props }, ref) => {
|
|
13
|
+
({ className, error, ...props }, ref) => {
|
|
11
14
|
return (
|
|
12
15
|
<textarea
|
|
13
16
|
className={cn(
|
|
14
|
-
'flex min-h-[80px] w-full rounded-
|
|
17
|
+
'flex min-h-[80px] w-full rounded-sm border bg-white px-3 py-2 text-base text-[var(--black)] ring-offset-background placeholder:text-gray-500 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm transition-colors resize-none',
|
|
18
|
+
error
|
|
19
|
+
? 'border-red-500 focus-visible:ring-red-500'
|
|
20
|
+
: 'border-gray-300 focus-visible:ring-[var(--cyan)]',
|
|
15
21
|
className
|
|
16
22
|
)}
|
|
17
23
|
ref={ref}
|
|
24
|
+
aria-invalid={error ? 'true' : undefined}
|
|
18
25
|
{...props}
|
|
19
26
|
/>
|
|
20
27
|
)
|
package/src/index.ts
CHANGED
|
@@ -113,6 +113,32 @@ export type {
|
|
|
113
113
|
SidebarNavItemProps,
|
|
114
114
|
} from './components/sidebar'
|
|
115
115
|
|
|
116
|
+
export { Alert, alertVariants } from './components/alert'
|
|
117
|
+
export type { AlertProps } from './components/alert'
|
|
118
|
+
|
|
119
|
+
export { EmptyState } from './components/empty-state'
|
|
120
|
+
export type { EmptyStateProps } from './components/empty-state'
|
|
121
|
+
|
|
122
|
+
export { CodeBlock } from './components/code-block'
|
|
123
|
+
export type { CodeBlockProps } from './components/code-block'
|
|
124
|
+
|
|
125
|
+
export { FormField } from './components/form-field'
|
|
126
|
+
export type { FormFieldProps } from './components/form-field'
|
|
127
|
+
|
|
128
|
+
export {
|
|
129
|
+
Table,
|
|
130
|
+
TableHeader,
|
|
131
|
+
TableBody,
|
|
132
|
+
TableFooter,
|
|
133
|
+
TableHead,
|
|
134
|
+
TableRow,
|
|
135
|
+
TableCell,
|
|
136
|
+
TableCaption,
|
|
137
|
+
} from './components/table'
|
|
138
|
+
|
|
139
|
+
export { Divider } from './components/divider'
|
|
140
|
+
export type { DividerProps } from './components/divider'
|
|
141
|
+
|
|
116
142
|
// Utilities
|
|
117
143
|
export { cn } from './lib/utils'
|
|
118
144
|
|