@umituz/web-design-system 1.5.1 → 1.7.2
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/package.json +14 -1
- package/src/presentation/atoms/Label.tsx +25 -0
- package/src/presentation/atoms/index.ts +2 -0
- package/src/presentation/molecules/ListItem.tsx +128 -0
- package/src/presentation/molecules/ScrollArea.tsx +50 -0
- package/src/presentation/molecules/index.ts +5 -0
- package/src/presentation/organisms/Alert.tsx +10 -19
- package/src/presentation/organisms/Collapsible.tsx +14 -0
- package/src/presentation/organisms/ConfirmDialog.tsx +97 -0
- package/src/presentation/organisms/DataTable.tsx +233 -0
- package/src/presentation/organisms/Dialog.tsx +124 -0
- package/src/presentation/organisms/EmptyState.tsx +103 -0
- package/src/presentation/organisms/FormModal.tsx +126 -0
- package/src/presentation/organisms/HoverCard.tsx +31 -0
- package/src/presentation/organisms/LoadingState.tsx +87 -0
- package/src/presentation/organisms/MetricCard.tsx +126 -0
- package/src/presentation/organisms/Popover.tsx +33 -0
- package/src/presentation/organisms/QuickActionCard.tsx +110 -0
- package/src/presentation/organisms/Sheet.tsx +135 -0
- package/src/presentation/organisms/StatCard.tsx +161 -0
- package/src/presentation/organisms/index.ts +54 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QuickActionCard Component (Organism)
|
|
3
|
+
* @description Card component for quick navigation actions with icon
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { forwardRef } from 'react';
|
|
7
|
+
import { cn } from '../../infrastructure/utils';
|
|
8
|
+
import type { BaseProps, SizeVariant } from '../../domain/types';
|
|
9
|
+
|
|
10
|
+
export interface QuickActionCardProps extends BaseProps {
|
|
11
|
+
label: string;
|
|
12
|
+
icon?: React.ComponentType<{ className?: string }>;
|
|
13
|
+
iconColor?: string;
|
|
14
|
+
iconBgColor?: string;
|
|
15
|
+
onClick?: () => void;
|
|
16
|
+
href?: string;
|
|
17
|
+
size?: Extract<SizeVariant, 'sm' | 'md' | 'lg'>;
|
|
18
|
+
target?: '_blank' | '_self' | '_parent' | '_top';
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const sizeStyles = {
|
|
22
|
+
sm: 'p-3 gap-2',
|
|
23
|
+
md: 'p-4 gap-3',
|
|
24
|
+
lg: 'p-5 gap-4',
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const iconSizeStyles = {
|
|
28
|
+
sm: 'w-8 h-8',
|
|
29
|
+
md: 'w-10 h-10',
|
|
30
|
+
lg: 'w-12 h-12',
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const iconInnerSizeStyles = {
|
|
34
|
+
sm: 'h-4 w-4',
|
|
35
|
+
md: 'h-5 w-5',
|
|
36
|
+
lg: 'h-6 w-6',
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const labelSizeStyles = {
|
|
40
|
+
sm: 'text-xs',
|
|
41
|
+
md: 'text-sm',
|
|
42
|
+
lg: 'text-base',
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export const QuickActionCard = forwardRef<HTMLAnchorElement | HTMLDivElement, QuickActionCardProps>(
|
|
46
|
+
(
|
|
47
|
+
{
|
|
48
|
+
className,
|
|
49
|
+
label,
|
|
50
|
+
icon: Icon,
|
|
51
|
+
iconColor = 'text-white',
|
|
52
|
+
iconBgColor = 'bg-primary',
|
|
53
|
+
onClick,
|
|
54
|
+
href,
|
|
55
|
+
size = 'md',
|
|
56
|
+
target = '_self',
|
|
57
|
+
...props
|
|
58
|
+
},
|
|
59
|
+
ref
|
|
60
|
+
) => {
|
|
61
|
+
const content = (
|
|
62
|
+
<>
|
|
63
|
+
{Icon && (
|
|
64
|
+
<div className={cn(iconSizeStyles[size], 'rounded-lg flex items-center justify-center flex-shrink-0', iconBgColor)}>
|
|
65
|
+
<Icon className={cn(iconInnerSizeStyles[size], iconColor)} />
|
|
66
|
+
</div>
|
|
67
|
+
)}
|
|
68
|
+
<span className={cn('font-medium text-foreground group-hover:text-primary transition-colors', labelSizeStyles[size])}>
|
|
69
|
+
{label}
|
|
70
|
+
</span>
|
|
71
|
+
</>
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
const baseClasses = cn(
|
|
75
|
+
'bg-card border border-border rounded-xl',
|
|
76
|
+
'flex items-center',
|
|
77
|
+
'hover:border-primary/50 transition-colors group',
|
|
78
|
+
sizeStyles[size],
|
|
79
|
+
className
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
if (href) {
|
|
83
|
+
return (
|
|
84
|
+
<a
|
|
85
|
+
ref={ref as React.Ref<HTMLAnchorElement>}
|
|
86
|
+
href={href}
|
|
87
|
+
target={target}
|
|
88
|
+
className={baseClasses}
|
|
89
|
+
onClick={onClick}
|
|
90
|
+
{...props}
|
|
91
|
+
>
|
|
92
|
+
{content}
|
|
93
|
+
</a>
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return (
|
|
98
|
+
<div
|
|
99
|
+
ref={ref as React.Ref<HTMLDivElement>}
|
|
100
|
+
className={baseClasses}
|
|
101
|
+
onClick={onClick}
|
|
102
|
+
{...props}
|
|
103
|
+
>
|
|
104
|
+
{content}
|
|
105
|
+
</div>
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
QuickActionCard.displayName = 'QuickActionCard';
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sheet Component (Organism)
|
|
3
|
+
* @description Slide-over sheet dialog (Shadcn/ui compatible)
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import * as SheetPrimitive from '@radix-ui/react-dialog';
|
|
7
|
+
import { X } from 'lucide-react';
|
|
8
|
+
import * as React from 'react';
|
|
9
|
+
import { cn } from '../../infrastructure/utils';
|
|
10
|
+
|
|
11
|
+
const Sheet = SheetPrimitive.Root;
|
|
12
|
+
|
|
13
|
+
const SheetTrigger = SheetPrimitive.Trigger;
|
|
14
|
+
|
|
15
|
+
const SheetClose = SheetPrimitive.Close;
|
|
16
|
+
|
|
17
|
+
const SheetPortal = SheetPrimitive.Portal;
|
|
18
|
+
|
|
19
|
+
const SheetOverlay = React.forwardRef<
|
|
20
|
+
React.ElementRef<typeof SheetPrimitive.Overlay>,
|
|
21
|
+
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Overlay>
|
|
22
|
+
>(({ className, ...props }, ref) => (
|
|
23
|
+
<SheetPrimitive.Overlay
|
|
24
|
+
className={cn(
|
|
25
|
+
'fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
|
|
26
|
+
className
|
|
27
|
+
)}
|
|
28
|
+
{...props}
|
|
29
|
+
ref={ref}
|
|
30
|
+
/>
|
|
31
|
+
));
|
|
32
|
+
SheetOverlay.displayName = SheetPrimitive.Overlay.displayName;
|
|
33
|
+
|
|
34
|
+
const getSheetVariants = (side: 'top' | 'bottom' | 'left' | 'right') => {
|
|
35
|
+
const base = 'fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500';
|
|
36
|
+
|
|
37
|
+
const sideVariants = {
|
|
38
|
+
top: 'inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top',
|
|
39
|
+
bottom: 'inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom',
|
|
40
|
+
left: 'inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm',
|
|
41
|
+
right: 'inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm',
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
return cn(base, sideVariants[side]);
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
interface SheetContentProps extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content> {
|
|
48
|
+
side?: 'top' | 'bottom' | 'left' | 'right';
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const SheetContent = React.forwardRef<
|
|
52
|
+
React.ElementRef<typeof SheetPrimitive.Content>,
|
|
53
|
+
SheetContentProps
|
|
54
|
+
>(({ side = 'right', className, children, ...props }, ref) => (
|
|
55
|
+
<SheetPortal>
|
|
56
|
+
<SheetOverlay />
|
|
57
|
+
<SheetPrimitive.Content
|
|
58
|
+
ref={ref}
|
|
59
|
+
className={cn(getSheetVariants(side), className)}
|
|
60
|
+
{...props}
|
|
61
|
+
>
|
|
62
|
+
{children}
|
|
63
|
+
<SheetPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary">
|
|
64
|
+
<X className="h-4 w-4" />
|
|
65
|
+
<span className="sr-only">Close</span>
|
|
66
|
+
</SheetPrimitive.Close>
|
|
67
|
+
</SheetPrimitive.Content>
|
|
68
|
+
</SheetPortal>
|
|
69
|
+
));
|
|
70
|
+
SheetContent.displayName = SheetPrimitive.Content.displayName;
|
|
71
|
+
|
|
72
|
+
const SheetHeader = ({
|
|
73
|
+
className,
|
|
74
|
+
...props
|
|
75
|
+
}: React.HTMLAttributes<HTMLDivElement>) => (
|
|
76
|
+
<div
|
|
77
|
+
className={cn(
|
|
78
|
+
'flex flex-col space-y-2 text-center sm:text-left',
|
|
79
|
+
className
|
|
80
|
+
)}
|
|
81
|
+
{...props}
|
|
82
|
+
/>
|
|
83
|
+
);
|
|
84
|
+
SheetHeader.displayName = 'SheetHeader';
|
|
85
|
+
|
|
86
|
+
const SheetFooter = ({
|
|
87
|
+
className,
|
|
88
|
+
...props
|
|
89
|
+
}: React.HTMLAttributes<HTMLDivElement>) => (
|
|
90
|
+
<div
|
|
91
|
+
className={cn(
|
|
92
|
+
'flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2',
|
|
93
|
+
className
|
|
94
|
+
)}
|
|
95
|
+
{...props}
|
|
96
|
+
/>
|
|
97
|
+
);
|
|
98
|
+
SheetFooter.displayName = 'SheetFooter';
|
|
99
|
+
|
|
100
|
+
const SheetTitle = React.forwardRef<
|
|
101
|
+
React.ElementRef<typeof SheetPrimitive.Title>,
|
|
102
|
+
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Title>
|
|
103
|
+
>(({ className, ...props }, ref) => (
|
|
104
|
+
<SheetPrimitive.Title
|
|
105
|
+
ref={ref}
|
|
106
|
+
className={cn('text-lg font-semibold text-foreground', className)}
|
|
107
|
+
{...props}
|
|
108
|
+
/>
|
|
109
|
+
));
|
|
110
|
+
SheetTitle.displayName = SheetPrimitive.Title.displayName;
|
|
111
|
+
|
|
112
|
+
const SheetDescription = React.forwardRef<
|
|
113
|
+
React.ElementRef<typeof SheetPrimitive.Description>,
|
|
114
|
+
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Description>
|
|
115
|
+
>(({ className, ...props }, ref) => (
|
|
116
|
+
<SheetPrimitive.Description
|
|
117
|
+
ref={ref}
|
|
118
|
+
className={cn('text-sm text-muted-foreground', className)}
|
|
119
|
+
{...props}
|
|
120
|
+
/>
|
|
121
|
+
));
|
|
122
|
+
SheetDescription.displayName = SheetPrimitive.Description.displayName;
|
|
123
|
+
|
|
124
|
+
export {
|
|
125
|
+
Sheet,
|
|
126
|
+
SheetClose,
|
|
127
|
+
SheetContent,
|
|
128
|
+
SheetDescription,
|
|
129
|
+
SheetFooter,
|
|
130
|
+
SheetHeader,
|
|
131
|
+
SheetOverlay,
|
|
132
|
+
SheetPortal,
|
|
133
|
+
SheetTitle,
|
|
134
|
+
SheetTrigger,
|
|
135
|
+
};
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* StatCard Component (Organism)
|
|
3
|
+
* @description Enhanced metric card with progress bar and target tracking
|
|
4
|
+
* Combines functionality of KPICard and StatsCard from main app
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { forwardRef, type ComponentType } from 'react';
|
|
8
|
+
import { cn } from '../../infrastructure/utils';
|
|
9
|
+
import { Card, CardContent } from './Card';
|
|
10
|
+
import { Progress } from '../atoms';
|
|
11
|
+
import { ArrowUpRight, ArrowDownRight } from 'lucide-react';
|
|
12
|
+
import type { BaseProps, ColorVariant, SizeVariant } from '../../domain/types';
|
|
13
|
+
|
|
14
|
+
export interface StatCardProps extends BaseProps {
|
|
15
|
+
title: string;
|
|
16
|
+
value: string | number;
|
|
17
|
+
icon?: ComponentType<{ className?: string }>;
|
|
18
|
+
iconColor?: string;
|
|
19
|
+
trend?: {
|
|
20
|
+
value: number;
|
|
21
|
+
label?: string;
|
|
22
|
+
};
|
|
23
|
+
target?: {
|
|
24
|
+
value: string;
|
|
25
|
+
progress: number;
|
|
26
|
+
};
|
|
27
|
+
size?: Extract<SizeVariant, 'sm' | 'md' | 'lg'>;
|
|
28
|
+
variant?: 'default' | 'gradient' | 'elevated';
|
|
29
|
+
trendValueFormatter?: (value: number) => string;
|
|
30
|
+
onClick?: () => void;
|
|
31
|
+
changeLabel?: string; // For backward compatibility with StatsCard
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const sizeStyles = {
|
|
35
|
+
sm: 'p-3',
|
|
36
|
+
md: 'p-4',
|
|
37
|
+
lg: 'p-6',
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const valueSizeStyles = {
|
|
41
|
+
sm: 'text-lg',
|
|
42
|
+
md: 'text-2xl',
|
|
43
|
+
lg: 'text-3xl',
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const iconSizeStyles = {
|
|
47
|
+
sm: 'h-4 w-4',
|
|
48
|
+
md: 'h-8 w-8',
|
|
49
|
+
lg: 'h-12 w-12',
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const labelSizeStyles = {
|
|
53
|
+
sm: 'text-xs',
|
|
54
|
+
md: 'text-sm',
|
|
55
|
+
lg: 'text-base',
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const iconBgSizeStyles = {
|
|
59
|
+
sm: 'w-8 h-8',
|
|
60
|
+
md: 'w-12 h-12',
|
|
61
|
+
lg: 'w-16 h-16',
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export const StatCard = forwardRef<HTMLDivElement, StatCardProps>(
|
|
65
|
+
(
|
|
66
|
+
{
|
|
67
|
+
className,
|
|
68
|
+
title,
|
|
69
|
+
value,
|
|
70
|
+
icon: Icon,
|
|
71
|
+
iconColor = 'text-primary',
|
|
72
|
+
trend,
|
|
73
|
+
target,
|
|
74
|
+
size = 'md',
|
|
75
|
+
variant = 'default',
|
|
76
|
+
trendValueFormatter = (v) => `${v > 0 ? '+' : ''}${Math.abs(v).toFixed(1)}%`,
|
|
77
|
+
onClick,
|
|
78
|
+
changeLabel,
|
|
79
|
+
...props
|
|
80
|
+
},
|
|
81
|
+
ref
|
|
82
|
+
) => {
|
|
83
|
+
const isPositive = trend?.value !== undefined && trend.value >= 0;
|
|
84
|
+
const GrowthIcon = isPositive ? ArrowUpRight : ArrowDownRight;
|
|
85
|
+
const trendColor = isPositive ? 'text-green-600' : 'text-red-600';
|
|
86
|
+
const iconBgColor = isPositive ? 'text-green-500' : 'text-red-500';
|
|
87
|
+
|
|
88
|
+
const cardVariant = variant === 'elevated' ? 'elevated' : 'default';
|
|
89
|
+
|
|
90
|
+
return (
|
|
91
|
+
<Card
|
|
92
|
+
ref={ref}
|
|
93
|
+
variant={cardVariant}
|
|
94
|
+
className={cn(
|
|
95
|
+
'transition-all duration-300',
|
|
96
|
+
variant === 'gradient' && 'bg-gradient-to-br from-white to-gray-50 hover:shadow-lg border-0 shadow-md',
|
|
97
|
+
onClick && 'cursor-pointer hover:shadow-lg hover:border-primary/50',
|
|
98
|
+
className
|
|
99
|
+
)}
|
|
100
|
+
onClick={onClick}
|
|
101
|
+
{...props}
|
|
102
|
+
>
|
|
103
|
+
<CardContent className={cn(sizeStyles[size])}>
|
|
104
|
+
<div className="flex items-center justify-between mb-4">
|
|
105
|
+
{Icon && (
|
|
106
|
+
<div
|
|
107
|
+
className={cn(
|
|
108
|
+
'rounded-xl flex items-center justify-center',
|
|
109
|
+
variant === 'gradient' && 'bg-gradient-to-br from-teal-500 to-cyan-500',
|
|
110
|
+
variant !== 'gradient' && `bg-${iconColor.split('-')[1]}-500/10`,
|
|
111
|
+
iconBgSizeStyles[size]
|
|
112
|
+
)}
|
|
113
|
+
>
|
|
114
|
+
<Icon className={cn(iconSizeStyles[size], variant === 'gradient' ? 'text-white' : iconColor)} />
|
|
115
|
+
</div>
|
|
116
|
+
)}
|
|
117
|
+
{trend && (
|
|
118
|
+
<span
|
|
119
|
+
className={cn(
|
|
120
|
+
'text-sm font-medium px-2 py-1 rounded-full',
|
|
121
|
+
isPositive ? 'text-green-700 bg-green-100' : 'text-red-700 bg-red-100'
|
|
122
|
+
)}
|
|
123
|
+
>
|
|
124
|
+
{changeLabel || trendValueFormatter(trend.value)}
|
|
125
|
+
</span>
|
|
126
|
+
)}
|
|
127
|
+
</div>
|
|
128
|
+
|
|
129
|
+
<div className="space-y-3">
|
|
130
|
+
<div>
|
|
131
|
+
<p className={cn('font-bold text-gray-900', valueSizeStyles[size])}>
|
|
132
|
+
{typeof value === 'number' ? value.toLocaleString() : value}
|
|
133
|
+
</p>
|
|
134
|
+
<p className={cn('text-muted-foreground', labelSizeStyles[size])}>{title}</p>
|
|
135
|
+
</div>
|
|
136
|
+
|
|
137
|
+
{target && (
|
|
138
|
+
<div className="space-y-1">
|
|
139
|
+
<div className="flex justify-between text-xs">
|
|
140
|
+
<span className="text-muted-foreground">Target: {target.value}</span>
|
|
141
|
+
<span className="text-teal-600">{target.progress}%</span>
|
|
142
|
+
</div>
|
|
143
|
+
<Progress value={target.progress} className="h-2" />
|
|
144
|
+
</div>
|
|
145
|
+
)}
|
|
146
|
+
|
|
147
|
+
{trend && variant !== 'gradient' && (
|
|
148
|
+
<div className="flex items-center mt-1">
|
|
149
|
+
<GrowthIcon className={cn('h-3 w-3 mr-1', iconBgColor)} />
|
|
150
|
+
<p className={cn('text-xs', trendColor)}>{trendValueFormatter(trend.value)}</p>
|
|
151
|
+
{trend.label && <p className="text-xs text-muted-foreground ml-1">{trend.label}</p>}
|
|
152
|
+
</div>
|
|
153
|
+
)}
|
|
154
|
+
</div>
|
|
155
|
+
</CardContent>
|
|
156
|
+
</Card>
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
StatCard.displayName = 'StatCard';
|
|
@@ -33,8 +33,62 @@ export type { TabsProps, Tab } from './Tabs';
|
|
|
33
33
|
|
|
34
34
|
export { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from './Accordion';
|
|
35
35
|
|
|
36
|
+
export {
|
|
37
|
+
Dialog,
|
|
38
|
+
DialogPortal,
|
|
39
|
+
DialogOverlay,
|
|
40
|
+
DialogClose,
|
|
41
|
+
DialogTrigger,
|
|
42
|
+
DialogContent,
|
|
43
|
+
DialogHeader,
|
|
44
|
+
DialogFooter,
|
|
45
|
+
DialogTitle,
|
|
46
|
+
DialogDescription,
|
|
47
|
+
} from './Dialog';
|
|
48
|
+
|
|
36
49
|
export { Breadcrumbs } from './Breadcrumb';
|
|
37
50
|
export type { BreadcrumbsProps, BreadcrumbItem } from './Breadcrumb';
|
|
38
51
|
|
|
52
|
+
export { Popover, PopoverTrigger, PopoverContent } from './Popover';
|
|
53
|
+
|
|
54
|
+
export { Collapsible, CollapsibleTrigger, CollapsibleContent } from './Collapsible';
|
|
55
|
+
|
|
56
|
+
export {
|
|
57
|
+
Sheet,
|
|
58
|
+
SheetClose,
|
|
59
|
+
SheetContent,
|
|
60
|
+
SheetDescription,
|
|
61
|
+
SheetFooter,
|
|
62
|
+
SheetHeader,
|
|
63
|
+
SheetOverlay,
|
|
64
|
+
SheetPortal,
|
|
65
|
+
SheetTitle,
|
|
66
|
+
SheetTrigger,
|
|
67
|
+
} from './Sheet';
|
|
68
|
+
|
|
39
69
|
export { Footer } from './Footer';
|
|
40
70
|
export type { FooterProps } from './Footer';
|
|
71
|
+
|
|
72
|
+
export { MetricCard } from './MetricCard';
|
|
73
|
+
export type { MetricCardProps } from './MetricCard';
|
|
74
|
+
|
|
75
|
+
export { QuickActionCard } from './QuickActionCard';
|
|
76
|
+
export type { QuickActionCardProps } from './QuickActionCard';
|
|
77
|
+
|
|
78
|
+
export { EmptyState } from './EmptyState';
|
|
79
|
+
export type { EmptyStateProps } from './EmptyState';
|
|
80
|
+
|
|
81
|
+
export { LoadingState } from './LoadingState';
|
|
82
|
+
export type { LoadingStateProps } from './LoadingState';
|
|
83
|
+
|
|
84
|
+
export { DataTable } from './DataTable';
|
|
85
|
+
export type { DataTableProps, Column } from './DataTable';
|
|
86
|
+
|
|
87
|
+
export { StatCard } from './StatCard';
|
|
88
|
+
export type { StatCardProps } from './StatCard';
|
|
89
|
+
|
|
90
|
+
export { FormModal } from './FormModal';
|
|
91
|
+
export type { FormModalProps } from './FormModal';
|
|
92
|
+
|
|
93
|
+
export { ConfirmDialog } from './ConfirmDialog';
|
|
94
|
+
export type { ConfirmDialogProps } from './ConfirmDialog';
|