@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.
Files changed (73) hide show
  1. package/dist/components/accordion.d.ts +8 -0
  2. package/dist/components/accordion.d.ts.map +1 -0
  3. package/dist/components/alert.d.ts +16 -0
  4. package/dist/components/alert.d.ts.map +1 -0
  5. package/dist/components/avatar.d.ts +7 -0
  6. package/dist/components/avatar.d.ts.map +1 -0
  7. package/dist/components/badge.d.ts +15 -0
  8. package/dist/components/badge.d.ts.map +1 -0
  9. package/dist/components/button.d.ts +16 -0
  10. package/dist/components/button.d.ts.map +1 -0
  11. package/dist/components/card.d.ts +9 -0
  12. package/dist/components/card.d.ts.map +1 -0
  13. package/dist/components/checkbox.d.ts +7 -0
  14. package/dist/components/checkbox.d.ts.map +1 -0
  15. package/dist/components/code-block.d.ts +10 -0
  16. package/dist/components/code-block.d.ts.map +1 -0
  17. package/dist/components/divider.d.ts +10 -0
  18. package/dist/components/divider.d.ts.map +1 -0
  19. package/dist/components/dropdown-menu.d.ts +28 -0
  20. package/dist/components/dropdown-menu.d.ts.map +1 -0
  21. package/dist/components/empty-state.d.ts +16 -0
  22. package/dist/components/empty-state.d.ts.map +1 -0
  23. package/dist/components/form-field.d.ts +20 -0
  24. package/dist/components/form-field.d.ts.map +1 -0
  25. package/dist/components/icon-box.d.ts +12 -0
  26. package/dist/components/icon-box.d.ts.map +1 -0
  27. package/dist/components/input.d.ts +8 -0
  28. package/dist/components/input.d.ts.map +1 -0
  29. package/dist/components/label.d.ts +7 -0
  30. package/dist/components/label.d.ts.map +1 -0
  31. package/dist/components/logo.d.ts +17 -0
  32. package/dist/components/logo.d.ts.map +1 -0
  33. package/dist/components/navigation-menu.d.ts +13 -0
  34. package/dist/components/navigation-menu.d.ts.map +1 -0
  35. package/dist/components/progress.d.ts +18 -0
  36. package/dist/components/progress.d.ts.map +1 -0
  37. package/dist/components/separator.d.ts +6 -0
  38. package/dist/components/separator.d.ts.map +1 -0
  39. package/dist/components/sheet.d.ts +26 -0
  40. package/dist/components/sheet.d.ts.map +1 -0
  41. package/dist/components/sidebar.d.ts +51 -0
  42. package/dist/components/sidebar.d.ts.map +1 -0
  43. package/dist/components/stat.d.ts +25 -0
  44. package/dist/components/stat.d.ts.map +1 -0
  45. package/dist/components/table.d.ts +11 -0
  46. package/dist/components/table.d.ts.map +1 -0
  47. package/dist/components/tag.d.ts +13 -0
  48. package/dist/components/tag.d.ts.map +1 -0
  49. package/dist/components/textarea.d.ts +8 -0
  50. package/dist/components/textarea.d.ts.map +1 -0
  51. package/dist/icons.d.ts +17 -0
  52. package/dist/icons.d.ts.map +1 -0
  53. package/dist/index.d.ts +46 -0
  54. package/dist/index.d.ts.map +1 -0
  55. package/dist/index.js +278 -10
  56. package/dist/index.js.map +1 -1
  57. package/dist/index.mjs +266 -12
  58. package/dist/index.mjs.map +1 -1
  59. package/dist/lib/utils.d.ts +3 -0
  60. package/dist/lib/utils.d.ts.map +1 -0
  61. package/package.json +2 -2
  62. package/src/components/alert.tsx +67 -0
  63. package/src/components/button.tsx +33 -2
  64. package/src/components/code-block.tsx +32 -0
  65. package/src/components/divider.tsx +52 -0
  66. package/src/components/dropdown-menu.tsx +3 -3
  67. package/src/components/empty-state.tsx +63 -0
  68. package/src/components/form-field.tsx +73 -0
  69. package/src/components/input.tsx +10 -3
  70. package/src/components/sidebar.tsx +4 -4
  71. package/src/components/table.tsx +108 -0
  72. package/src/components/textarea.tsx +10 -3
  73. 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-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
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-2 py-1.5 text-sm font-semibold",
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 }
@@ -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-md border border-gray-300 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-[var(--cyan)] focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm transition-colors',
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: 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?: 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<any, SidebarNavItemProps>(
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-md border border-gray-300 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-[var(--cyan)] focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm transition-colors',
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