@schandlergarcia/sf-web-components 1.9.38 → 1.9.39

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 (109) hide show
  1. package/package.json +4 -1
  2. package/scripts/postinstall.mjs +36 -17
  3. package/src/components/library/cards/ActionList.jsx +38 -0
  4. package/src/components/library/cards/ActivityCard.jsx +56 -0
  5. package/src/components/library/cards/BaseCard.jsx +109 -0
  6. package/src/components/library/cards/CalloutCard.jsx +37 -0
  7. package/src/components/library/cards/ChartCard.jsx +105 -0
  8. package/src/components/library/cards/FeedPanel.jsx +39 -0
  9. package/src/components/library/cards/ListCard.jsx +193 -0
  10. package/src/components/library/cards/MetricCard.jsx +109 -0
  11. package/src/components/library/cards/MetricsStrip.jsx +78 -0
  12. package/src/components/library/cards/SectionCard.jsx +83 -0
  13. package/src/components/library/cards/SemanticMetricCard.jsx +52 -0
  14. package/src/components/library/cards/SemanticMetricCardWithLoading.jsx +23 -0
  15. package/src/components/library/cards/SemanticTableCard.jsx +48 -0
  16. package/src/components/library/cards/SemanticTableCardWithLoading.jsx +22 -0
  17. package/src/components/library/cards/StatusCard.jsx +220 -0
  18. package/src/components/library/cards/TableCard.jsx +337 -0
  19. package/src/components/library/cards/WidgetCard.jsx +90 -0
  20. package/src/components/library/charts/D3Chart.jsx +109 -0
  21. package/src/components/library/charts/D3ChartTemplates.jsx +126 -0
  22. package/src/components/library/charts/GeoMap.jsx +293 -0
  23. package/src/components/library/chat/ChatBar.jsx +256 -0
  24. package/src/components/library/chat/ChatInput.jsx +89 -0
  25. package/src/components/library/chat/ChatMessage.jsx +178 -0
  26. package/src/components/library/chat/ChatMessageList.jsx +73 -0
  27. package/src/components/library/chat/ChatPanel.jsx +97 -0
  28. package/src/components/library/chat/ChatSuggestions.jsx +28 -0
  29. package/src/components/library/chat/ChatToolCall.jsx +100 -0
  30. package/src/components/library/chat/ChatTypingIndicator.jsx +23 -0
  31. package/src/components/library/chat/ChatWelcome.jsx +43 -0
  32. package/src/components/library/chat/index.jsx +10 -0
  33. package/src/components/library/chat/useChatState.jsx +130 -0
  34. package/src/components/library/data/DataModeProvider.jsx +67 -0
  35. package/src/components/library/data/DataModeToggle.jsx +36 -0
  36. package/src/components/library/data/chartDataProvider.jsx +61 -0
  37. package/src/components/library/data/filterUtils.jsx +141 -0
  38. package/src/components/library/data/useDataSource.jsx +33 -0
  39. package/src/components/library/data/usePageFilters.jsx +99 -0
  40. package/src/components/library/filters/FilterBar.jsx +95 -0
  41. package/src/components/library/filters/SearchFilter.jsx +36 -0
  42. package/src/components/library/filters/SelectFilter.jsx +55 -0
  43. package/src/components/library/filters/ToggleFilter.jsx +52 -0
  44. package/src/components/library/filters/index.jsx +4 -0
  45. package/src/components/library/forms/FormField.jsx +291 -0
  46. package/src/components/library/forms/FormModal.jsx +201 -0
  47. package/src/components/library/forms/FormRenderer.jsx +46 -0
  48. package/src/components/library/forms/FormSection.jsx +69 -0
  49. package/src/components/library/forms/index.jsx +5 -0
  50. package/src/components/library/forms/useFormState.jsx +165 -0
  51. package/src/components/library/heroui/Accordion.jsx +26 -0
  52. package/src/components/library/heroui/Alert.jsx +8 -0
  53. package/src/components/library/heroui/Badge.jsx +8 -0
  54. package/src/components/library/heroui/Breadcrumbs.jsx +22 -0
  55. package/src/components/library/heroui/Button.jsx +58 -0
  56. package/src/components/library/heroui/Card.jsx +8 -0
  57. package/src/components/library/heroui/Collapsible.jsx +42 -0
  58. package/src/components/library/heroui/DatePicker.jsx +34 -0
  59. package/src/components/library/heroui/Dialog.jsx +37 -0
  60. package/src/components/library/heroui/Drawer.jsx +32 -0
  61. package/src/components/library/heroui/Dropdown.jsx +28 -0
  62. package/src/components/library/heroui/Field.jsx +51 -0
  63. package/src/components/library/heroui/Input.jsx +6 -0
  64. package/src/components/library/heroui/Kbd.jsx +8 -0
  65. package/src/components/library/heroui/Meter.jsx +8 -0
  66. package/src/components/library/heroui/Modal.jsx +32 -0
  67. package/src/components/library/heroui/Pagination.jsx +8 -0
  68. package/src/components/library/heroui/Popover.jsx +64 -0
  69. package/src/components/library/heroui/ProgressBar.jsx +8 -0
  70. package/src/components/library/heroui/ProgressCircle.jsx +8 -0
  71. package/src/components/library/heroui/ScrollShadow.jsx +8 -0
  72. package/src/components/library/heroui/Select.jsx +37 -0
  73. package/src/components/library/heroui/Separator.jsx +8 -0
  74. package/src/components/library/heroui/Skeleton.jsx +8 -0
  75. package/src/components/library/heroui/Tabs.jsx +26 -0
  76. package/src/components/library/heroui/Toast.jsx +25 -0
  77. package/src/components/library/heroui/Toggle.jsx +14 -0
  78. package/src/components/library/heroui/Tooltip.jsx +21 -0
  79. package/src/components/library/index.jsx +146 -0
  80. package/src/components/library/layout/PageContainer.jsx +11 -0
  81. package/src/components/library/skeletons/CardSkeleton.jsx +30 -0
  82. package/src/components/library/theme/AppThemeProvider.jsx +67 -0
  83. package/src/components/library/theme/tokens.jsx +72 -0
  84. package/src/components/library/ui/Alert.jsx +80 -0
  85. package/src/components/library/ui/Avatar.jsx +44 -0
  86. package/src/components/library/ui/BreadcrumbExtras.tsx +120 -0
  87. package/src/components/library/ui/Button.jsx +61 -0
  88. package/src/components/library/ui/Card.jsx +117 -0
  89. package/src/components/library/ui/Checkbox.jsx +17 -0
  90. package/src/components/library/ui/Chip.jsx +38 -0
  91. package/src/components/library/ui/Collapsible.tsx +31 -0
  92. package/src/components/library/ui/Container.jsx +56 -0
  93. package/src/components/library/ui/DatePicker.tsx +34 -0
  94. package/src/components/library/ui/Dialog.tsx +141 -0
  95. package/src/components/library/ui/EmptyState.jsx +46 -0
  96. package/src/components/library/ui/Field.tsx +82 -0
  97. package/src/components/library/ui/FieldGroup.jsx +17 -0
  98. package/src/components/library/ui/Input.jsx +21 -0
  99. package/src/components/library/ui/Label.jsx +22 -0
  100. package/src/components/library/ui/PaginationExtras.tsx +142 -0
  101. package/src/components/library/ui/Popover.tsx +39 -0
  102. package/src/components/library/ui/Select.tsx +113 -0
  103. package/src/components/library/ui/Spinner.d.ts +10 -0
  104. package/src/components/library/ui/Spinner.jsx +64 -0
  105. package/src/components/library/ui/Text.jsx +46 -0
  106. package/src/components/library/ui/Toggle.jsx +42 -0
  107. package/src/components/workspace/ComponentRegistry.jsx +297 -0
  108. package/src/lib/index.ts +1 -0
  109. package/src/lib/utils.ts +6 -0
@@ -0,0 +1,120 @@
1
+ import * as React from "react";
2
+ import { Link } from "react-router-dom";
3
+
4
+ // Shadcn-style Breadcrumb subcomponents to work with HeroUI Breadcrumbs
5
+
6
+ function Breadcrumb({ className, children, ...props }: React.ComponentProps<"nav">) {
7
+ return (
8
+ <nav aria-label="breadcrumb" className={className} {...props}>
9
+ {children}
10
+ </nav>
11
+ );
12
+ }
13
+
14
+ function BreadcrumbList({ className, children, ...props }: React.ComponentProps<"ol">) {
15
+ return (
16
+ <ol
17
+ className={[
18
+ "flex flex-wrap items-center gap-1.5 break-words text-sm text-slate-500 dark:text-slate-400",
19
+ className
20
+ ].filter(Boolean).join(" ")}
21
+ {...props}
22
+ >
23
+ {children}
24
+ </ol>
25
+ );
26
+ }
27
+
28
+ function BreadcrumbItem({ className, children, ...props }: React.ComponentProps<"li">) {
29
+ return (
30
+ <li
31
+ className={[
32
+ "inline-flex items-center gap-1.5",
33
+ className
34
+ ].filter(Boolean).join(" ")}
35
+ {...props}
36
+ >
37
+ {children}
38
+ </li>
39
+ );
40
+ }
41
+
42
+ function BreadcrumbLink({ className, href, children, ...props }: React.ComponentProps<typeof Link>) {
43
+ return (
44
+ <Link
45
+ to={href || "#"}
46
+ className={[
47
+ "transition-colors hover:text-slate-900 dark:hover:text-slate-50",
48
+ className
49
+ ].filter(Boolean).join(" ")}
50
+ {...props}
51
+ >
52
+ {children}
53
+ </Link>
54
+ );
55
+ }
56
+
57
+ function BreadcrumbPage({ className, children, ...props }: React.ComponentProps<"span">) {
58
+ return (
59
+ <span
60
+ role="link"
61
+ aria-disabled="true"
62
+ aria-current="page"
63
+ className={[
64
+ "font-normal text-slate-900 dark:text-slate-50",
65
+ className
66
+ ].filter(Boolean).join(" ")}
67
+ {...props}
68
+ >
69
+ {children}
70
+ </span>
71
+ );
72
+ }
73
+
74
+ function BreadcrumbSeparator({ children, className, ...props }: React.ComponentProps<"li">) {
75
+ return (
76
+ <li
77
+ role="presentation"
78
+ aria-hidden="true"
79
+ className={[
80
+ "select-none",
81
+ className
82
+ ].filter(Boolean).join(" ")}
83
+ {...props}
84
+ >
85
+ {children ?? "/"}
86
+ </li>
87
+ );
88
+ }
89
+
90
+ function BreadcrumbEllipsis({ className, ...props }: React.ComponentProps<"span">) {
91
+ return (
92
+ <span
93
+ role="presentation"
94
+ aria-hidden="true"
95
+ className={[
96
+ "flex h-9 w-9 items-center justify-center",
97
+ className
98
+ ].filter(Boolean).join(" ")}
99
+ {...props}
100
+ >
101
+ <svg width="15" height="15" viewBox="0 0 15 15" fill="none">
102
+ <path
103
+ d="M3.625 7.5C3.625 8.12132 3.12132 8.625 2.5 8.625C1.87868 8.625 1.375 8.12132 1.375 7.5C1.375 6.87868 1.87868 6.375 2.5 6.375C3.12132 6.375 3.625 6.87868 3.625 7.5ZM8.625 7.5C8.625 8.12132 8.12132 8.625 7.5 8.625C6.87868 8.625 6.375 8.12132 6.375 7.5C6.375 6.87868 6.87868 6.375 7.5 6.375C8.12132 6.375 8.625 6.87868 8.625 7.5ZM12.5 8.625C13.1213 8.625 13.625 8.12132 13.625 7.5C13.625 6.87868 13.1213 6.375 12.5 6.375C11.8787 6.375 11.375 6.87868 11.375 7.5C11.375 8.12132 11.8787 8.625 12.5 8.625Z"
104
+ fill="currentColor"
105
+ />
106
+ </svg>
107
+ <span className="sr-only">More</span>
108
+ </span>
109
+ );
110
+ }
111
+
112
+ export {
113
+ Breadcrumb,
114
+ BreadcrumbList,
115
+ BreadcrumbItem,
116
+ BreadcrumbLink,
117
+ BreadcrumbPage,
118
+ BreadcrumbSeparator,
119
+ BreadcrumbEllipsis,
120
+ };
@@ -0,0 +1,61 @@
1
+ import React from "react";
2
+
3
+ const VARIANT_CLASSES = {
4
+ primary:
5
+ "bg-brand-600 text-white hover:bg-brand-500 dark:bg-brand-500 dark:hover:bg-brand-400 border-transparent",
6
+ secondary:
7
+ "bg-slate-900 text-white hover:bg-slate-800 dark:bg-slate-100 dark:text-slate-900 dark:hover:bg-slate-200 border-transparent",
8
+ destructive:
9
+ "bg-red-600 text-white hover:bg-red-500 dark:bg-red-500 dark:hover:bg-red-400 border-transparent",
10
+ outline:
11
+ "bg-transparent text-slate-900 hover:bg-slate-50 dark:text-slate-50 dark:hover:bg-slate-900 border-slate-200 dark:border-slate-800",
12
+ ghost:
13
+ "bg-transparent text-slate-900 hover:bg-slate-100 dark:text-slate-50 dark:hover:bg-slate-900 border-transparent"
14
+ };
15
+
16
+ const SIZE_CLASSES = {
17
+ sm: "h-8 px-3 text-sm",
18
+ md: "h-10 px-4 text-sm",
19
+ lg: "h-12 px-5 text-base",
20
+ icon: "h-10 w-10 p-0"
21
+ };
22
+
23
+ export default function UIButton({
24
+ variant = "primary",
25
+ size = "md",
26
+ fullWidth = false,
27
+ disabled = false,
28
+ onClick = () => {},
29
+ children,
30
+ style = undefined,
31
+ className = "",
32
+ ...rest
33
+ }) {
34
+ const variantClass = VARIANT_CLASSES[variant] ?? VARIANT_CLASSES.primary;
35
+ const sizeClass = SIZE_CLASSES[size] ?? SIZE_CLASSES.md;
36
+
37
+ return (
38
+ <button
39
+ type="button"
40
+ onClick={onClick}
41
+ disabled={disabled}
42
+ style={style}
43
+ className={[
44
+ "inline-flex items-center justify-center gap-2 rounded-lg border font-medium shadow-sm transition",
45
+ "focus:outline-none focus-visible:ring-2 focus-visible:ring-brand-500 focus-visible:ring-offset-2 dark:focus-visible:ring-offset-slate-950",
46
+ "disabled:cursor-not-allowed disabled:opacity-60",
47
+ variantClass,
48
+ sizeClass,
49
+ fullWidth ? "w-full" : "",
50
+ className
51
+ ]
52
+ .filter(Boolean)
53
+ .join(" ")}
54
+ {...rest}
55
+ >
56
+ {children}
57
+ </button>
58
+ );
59
+ }
60
+
61
+
@@ -0,0 +1,117 @@
1
+ import React from "react";
2
+
3
+ export default function UICard({ children, padding = "p-5", style, className = "", ...rest }) {
4
+ return (
5
+ <div
6
+ style={style}
7
+ className={[
8
+ "rounded-2xl border border-slate-200 bg-white shadow-sm dark:border-slate-800 dark:bg-slate-900",
9
+ padding,
10
+ className
11
+ ]
12
+ .filter(Boolean)
13
+ .join(" ")}
14
+ {...rest}
15
+ >
16
+ {children}
17
+ </div>
18
+ );
19
+ }
20
+
21
+ // shadcn-compatible Card components
22
+ export function Card({ className = "", children, ...rest }) {
23
+ return (
24
+ <div
25
+ className={[
26
+ "rounded-2xl border border-slate-200 bg-white shadow-sm dark:border-slate-800 dark:bg-slate-900",
27
+ className
28
+ ]
29
+ .filter(Boolean)
30
+ .join(" ")}
31
+ {...rest}
32
+ >
33
+ {children}
34
+ </div>
35
+ );
36
+ }
37
+
38
+ export function CardHeader({ className = "", children, ...rest }) {
39
+ return (
40
+ <div
41
+ className={[
42
+ "flex flex-col space-y-1.5 p-6",
43
+ className
44
+ ]
45
+ .filter(Boolean)
46
+ .join(" ")}
47
+ {...rest}
48
+ >
49
+ {children}
50
+ </div>
51
+ );
52
+ }
53
+
54
+ export function CardTitle({ className = "", children, ...rest }) {
55
+ return (
56
+ <h3
57
+ className={[
58
+ "text-2xl font-semibold leading-none tracking-tight",
59
+ className
60
+ ]
61
+ .filter(Boolean)
62
+ .join(" ")}
63
+ {...rest}
64
+ >
65
+ {children}
66
+ </h3>
67
+ );
68
+ }
69
+
70
+ export function CardDescription({ className = "", children, ...rest }) {
71
+ return (
72
+ <p
73
+ className={[
74
+ "text-sm text-slate-500 dark:text-slate-400",
75
+ className
76
+ ]
77
+ .filter(Boolean)
78
+ .join(" ")}
79
+ {...rest}
80
+ >
81
+ {children}
82
+ </p>
83
+ );
84
+ }
85
+
86
+ export function CardContent({ className = "", children, ...rest }) {
87
+ return (
88
+ <div
89
+ className={[
90
+ "p-6 pt-0",
91
+ className
92
+ ]
93
+ .filter(Boolean)
94
+ .join(" ")}
95
+ {...rest}
96
+ >
97
+ {children}
98
+ </div>
99
+ );
100
+ }
101
+
102
+ export function CardFooter({ className = "", children, ...rest }) {
103
+ return (
104
+ <div
105
+ className={[
106
+ "flex items-center p-6 pt-0",
107
+ className
108
+ ]
109
+ .filter(Boolean)
110
+ .join(" ")}
111
+ {...rest}
112
+ >
113
+ {children}
114
+ </div>
115
+ );
116
+ }
117
+
@@ -0,0 +1,17 @@
1
+ import React from "react";
2
+
3
+ export default function Checkbox({ className = "", ...rest }) {
4
+ return (
5
+ <input
6
+ type="checkbox"
7
+ className={[
8
+ "h-4 w-4 rounded border-slate-300 text-brand-600 focus:ring-brand-500",
9
+ "dark:border-slate-600 dark:bg-slate-800 dark:focus:ring-brand-400",
10
+ className
11
+ ]
12
+ .filter(Boolean)
13
+ .join(" ")}
14
+ {...rest}
15
+ />
16
+ );
17
+ }
@@ -0,0 +1,38 @@
1
+ import React from "react";
2
+
3
+ const TONE_STYLES = {
4
+ neutral:
5
+ "border-slate-200/80 bg-white/60 text-slate-700 ring-black/5 hover:bg-white/80 dark:border-slate-800/80 dark:bg-slate-950/30 dark:text-slate-200 dark:ring-white/10 dark:hover:bg-slate-900/50",
6
+ primary:
7
+ "border-brand-200/80 bg-brand-50/70 text-brand-800 ring-brand-900/5 hover:bg-brand-50 dark:border-brand-900/40 dark:bg-brand-950/25 dark:text-brand-200 dark:ring-brand-300/10 dark:hover:bg-brand-950/35",
8
+ success:
9
+ "border-emerald-200/80 bg-emerald-50/70 text-emerald-800 ring-emerald-900/5 hover:bg-emerald-50 dark:border-emerald-900/40 dark:bg-emerald-950/20 dark:text-emerald-200 dark:ring-emerald-300/10 dark:hover:bg-emerald-950/30",
10
+ warning:
11
+ "border-amber-200/80 bg-amber-50/70 text-amber-900 ring-amber-900/5 hover:bg-amber-50 dark:border-amber-900/40 dark:bg-amber-950/20 dark:text-amber-200 dark:ring-amber-300/10 dark:hover:bg-amber-950/30",
12
+ danger:
13
+ "border-rose-200/80 bg-rose-50/70 text-rose-900 ring-rose-900/5 hover:bg-rose-50 dark:border-rose-900/40 dark:bg-rose-950/20 dark:text-rose-200 dark:ring-rose-300/10 dark:hover:bg-rose-950/30"
14
+ };
15
+
16
+ const SIZE_STYLES = {
17
+ xs: "px-2 py-0.5 text-[11px]",
18
+ sm: "px-2.5 py-1 text-xs"
19
+ };
20
+
21
+ export default function UIChip({ tone = "neutral", size = "xs", className = "", children, ...rest }) {
22
+ return (
23
+ <span
24
+ className={[
25
+ "inline-flex items-center gap-1 rounded-full border font-semibold shadow-sm ring-1 transition",
26
+ SIZE_STYLES[size] ?? SIZE_STYLES.xs,
27
+ TONE_STYLES[tone] ?? TONE_STYLES.neutral,
28
+ className
29
+ ]
30
+ .filter(Boolean)
31
+ .join(" ")}
32
+ {...rest}
33
+ >
34
+ {children}
35
+ </span>
36
+ );
37
+ }
38
+
@@ -0,0 +1,31 @@
1
+ import * as React from "react";
2
+ import { Collapsible as CollapsiblePrimitive } from "radix-ui";
3
+
4
+ function Collapsible({ ...props }: React.ComponentProps<typeof CollapsiblePrimitive.Root>) {
5
+ return <CollapsiblePrimitive.Root {...props} />;
6
+ }
7
+
8
+ function CollapsibleTrigger({ ...props }: React.ComponentProps<typeof CollapsiblePrimitive.Trigger>) {
9
+ return <CollapsiblePrimitive.Trigger {...props} />;
10
+ }
11
+
12
+ function CollapsibleContent({
13
+ className,
14
+ ...props
15
+ }: React.ComponentProps<typeof CollapsiblePrimitive.Content>) {
16
+ return (
17
+ <CollapsiblePrimitive.Content
18
+ className={[
19
+ "overflow-hidden data-[state=closed]:animate-out data-[state=open]:animate-in",
20
+ className
21
+ ].filter(Boolean).join(" ")}
22
+ {...props}
23
+ />
24
+ );
25
+ }
26
+
27
+ export {
28
+ Collapsible,
29
+ CollapsibleTrigger,
30
+ CollapsibleContent,
31
+ };
@@ -0,0 +1,56 @@
1
+ import React from "react";
2
+ import UIText from "./Text";
3
+
4
+ export default function UIContainer({
5
+ title,
6
+ subtitle,
7
+ description,
8
+ actions,
9
+ empty = false,
10
+ emptyText = "Nothing here yet.",
11
+ emptyIcon,
12
+ emptyHeight = 160,
13
+ className = "",
14
+ style,
15
+ children
16
+ }) {
17
+ const sub = subtitle ?? description;
18
+
19
+ return (
20
+ <section className={className} style={style}>
21
+ {(title || sub || actions) && (
22
+ <div className="mb-4 flex flex-col gap-2 sm:flex-row sm:items-end sm:justify-between">
23
+ <div className="min-w-0">
24
+ {title && (
25
+ <UIText as="h2" size="lg" weight="bold" className="truncate">
26
+ {title}
27
+ </UIText>
28
+ )}
29
+ {sub && (
30
+ <UIText as="p" size="sm" muted className="mt-1">
31
+ {sub}
32
+ </UIText>
33
+ )}
34
+ </div>
35
+ {actions && <div className="flex shrink-0 items-center gap-2">{actions}</div>}
36
+ </div>
37
+ )}
38
+
39
+ {empty ? (
40
+ <div
41
+ className="flex w-full flex-col items-center justify-center rounded-2xl border border-dashed border-slate-300 bg-slate-50 px-6 text-center dark:border-slate-700 dark:bg-slate-900/40"
42
+ style={{ minHeight: emptyHeight }}
43
+ >
44
+ {emptyIcon ? <div className="mb-2">{emptyIcon}</div> : null}
45
+ <UIText size="sm" muted>
46
+ {emptyText}
47
+ </UIText>
48
+ </div>
49
+ ) : (
50
+ children
51
+ )}
52
+ </section>
53
+ );
54
+ }
55
+
56
+
@@ -0,0 +1,34 @@
1
+ import * as React from "react";
2
+ import { Popover, PopoverContent, PopoverTrigger } from "./Popover";
3
+
4
+ // Simplified DatePicker components
5
+ // Full implementation would use react-day-picker
6
+
7
+ function DatePicker({ children, ...props }: { children: React.ReactNode } & React.ComponentProps<typeof Popover>) {
8
+ return <Popover {...props}>{children}</Popover>;
9
+ }
10
+
11
+ function DatePickerTrigger({ ...props }: React.ComponentProps<typeof PopoverTrigger>) {
12
+ return <PopoverTrigger {...props} />;
13
+ }
14
+
15
+ function DatePickerContent({ ...props }: React.ComponentProps<typeof PopoverContent>) {
16
+ return <PopoverContent {...props} />;
17
+ }
18
+
19
+ function DatePickerCalendar({ ...props }: any) {
20
+ // Simplified calendar placeholder
21
+ return <div {...props}>Calendar component</div>;
22
+ }
23
+
24
+ function DatePickerRangeTrigger({ ...props }: React.ComponentProps<typeof PopoverTrigger>) {
25
+ return <PopoverTrigger {...props} />;
26
+ }
27
+
28
+ export {
29
+ DatePicker,
30
+ DatePickerTrigger,
31
+ DatePickerContent,
32
+ DatePickerCalendar,
33
+ DatePickerRangeTrigger,
34
+ };
@@ -0,0 +1,141 @@
1
+ import * as React from "react";
2
+ import { Dialog as DialogPrimitive } from "radix-ui";
3
+
4
+ function Dialog({ ...props }: React.ComponentProps<typeof DialogPrimitive.Root>) {
5
+ return <DialogPrimitive.Root {...props} />;
6
+ }
7
+
8
+ function DialogTrigger({ ...props }: React.ComponentProps<typeof DialogPrimitive.Trigger>) {
9
+ return <DialogPrimitive.Trigger {...props} />;
10
+ }
11
+
12
+ function DialogPortal({ ...props }: React.ComponentProps<typeof DialogPrimitive.Portal>) {
13
+ return <DialogPrimitive.Portal {...props} />;
14
+ }
15
+
16
+ function DialogClose({ ...props }: React.ComponentProps<typeof DialogPrimitive.Close>) {
17
+ return <DialogPrimitive.Close {...props} />;
18
+ }
19
+
20
+ function DialogOverlay({
21
+ className,
22
+ ...props
23
+ }: React.ComponentProps<typeof DialogPrimitive.Overlay>) {
24
+ return (
25
+ <DialogPrimitive.Overlay
26
+ className={[
27
+ "fixed inset-0 z-50 bg-black/50",
28
+ className
29
+ ].filter(Boolean).join(" ")}
30
+ {...props}
31
+ />
32
+ );
33
+ }
34
+
35
+ function DialogContent({
36
+ className,
37
+ children,
38
+ showCloseButton = true,
39
+ ...props
40
+ }: React.ComponentProps<typeof DialogPrimitive.Content> & { showCloseButton?: boolean }) {
41
+ return (
42
+ <DialogPortal>
43
+ <DialogOverlay />
44
+ <DialogPrimitive.Content
45
+ className={[
46
+ "fixed left-1/2 top-1/2 z-50 max-h-[85vh] w-[90vw] max-w-[500px] -translate-x-1/2 -translate-y-1/2",
47
+ "rounded-lg border border-slate-200 bg-white p-6 shadow-lg",
48
+ "dark:border-slate-800 dark:bg-slate-900",
49
+ className
50
+ ].filter(Boolean).join(" ")}
51
+ {...props}
52
+ >
53
+ {children}
54
+ {showCloseButton && (
55
+ <DialogClose className="absolute right-4 top-4 rounded-sm opacity-70 hover:opacity-100">
56
+ <span className="sr-only">Close</span>
57
+ <svg width="15" height="15" viewBox="0 0 15 15" fill="none">
58
+ <path
59
+ d="M11.7816 4.03157C12.0062 3.80702 12.0062 3.44295 11.7816 3.2184C11.5571 2.99385 11.193 2.99385 10.9685 3.2184L7.50005 6.68682L4.03164 3.2184C3.80708 2.99385 3.44301 2.99385 3.21846 3.2184C2.99391 3.44295 2.99391 3.80702 3.21846 4.03157L6.68688 7.49999L3.21846 10.9684C2.99391 11.193 2.99391 11.557 3.21846 11.7816C3.44301 12.0061 3.80708 12.0061 4.03164 11.7816L7.50005 8.31316L10.9685 11.7816C11.193 12.0061 11.5571 12.0061 11.7816 11.7816C12.0062 11.557 12.0062 11.193 11.7816 10.9684L8.31322 7.49999L11.7816 4.03157Z"
60
+ fill="currentColor"
61
+ />
62
+ </svg>
63
+ </DialogClose>
64
+ )}
65
+ </DialogPrimitive.Content>
66
+ </DialogPortal>
67
+ );
68
+ }
69
+
70
+ function DialogHeader({
71
+ className,
72
+ ...props
73
+ }: React.ComponentProps<"div">) {
74
+ return (
75
+ <div
76
+ className={[
77
+ "flex flex-col space-y-1.5 text-center sm:text-left",
78
+ className
79
+ ].filter(Boolean).join(" ")}
80
+ {...props}
81
+ />
82
+ );
83
+ }
84
+
85
+ function DialogFooter({
86
+ className,
87
+ ...props
88
+ }: React.ComponentProps<"div">) {
89
+ return (
90
+ <div
91
+ className={[
92
+ "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
93
+ className
94
+ ].filter(Boolean).join(" ")}
95
+ {...props}
96
+ />
97
+ );
98
+ }
99
+
100
+ function DialogTitle({
101
+ className,
102
+ ...props
103
+ }: React.ComponentProps<typeof DialogPrimitive.Title>) {
104
+ return (
105
+ <DialogPrimitive.Title
106
+ className={[
107
+ "text-lg font-semibold leading-none tracking-tight",
108
+ className
109
+ ].filter(Boolean).join(" ")}
110
+ {...props}
111
+ />
112
+ );
113
+ }
114
+
115
+ function DialogDescription({
116
+ className,
117
+ ...props
118
+ }: React.ComponentProps<typeof DialogPrimitive.Description>) {
119
+ return (
120
+ <DialogPrimitive.Description
121
+ className={[
122
+ "text-sm text-slate-500 dark:text-slate-400",
123
+ className
124
+ ].filter(Boolean).join(" ")}
125
+ {...props}
126
+ />
127
+ );
128
+ }
129
+
130
+ export {
131
+ Dialog,
132
+ DialogTrigger,
133
+ DialogPortal,
134
+ DialogClose,
135
+ DialogOverlay,
136
+ DialogContent,
137
+ DialogHeader,
138
+ DialogFooter,
139
+ DialogTitle,
140
+ DialogDescription,
141
+ };
@@ -0,0 +1,46 @@
1
+ import React from "react";
2
+
3
+ const SIZES = {
4
+ sm: { icon: "h-8 w-8", heading: "text-sm", body: "text-xs", gap: "gap-2", pad: "py-6" },
5
+ md: { icon: "h-10 w-10", heading: "text-base", body: "text-sm", gap: "gap-3", pad: "py-10" },
6
+ lg: { icon: "h-14 w-14", heading: "text-lg", body: "text-sm", gap: "gap-4", pad: "py-16" },
7
+ };
8
+
9
+ /**
10
+ * Empty state placeholder — shows when a list, table, or section has no content.
11
+ *
12
+ * @param {ReactNode} icon Optional icon element
13
+ * @param {string} heading Primary message
14
+ * @param {string} body Secondary description
15
+ * @param {ReactNode} action Optional CTA (button, link, etc.)
16
+ * @param {"sm"|"md"|"lg"} size Visual density
17
+ */
18
+ export default function EmptyState({
19
+ icon,
20
+ heading = "Nothing here yet",
21
+ body,
22
+ action,
23
+ size = "md",
24
+ className = "",
25
+ }) {
26
+ const s = SIZES[size] ?? SIZES.md;
27
+
28
+ return (
29
+ <div className={`flex flex-col items-center justify-center text-center ${s.pad} ${s.gap} ${className}`}>
30
+ {icon && (
31
+ <div className={`${s.icon} text-slate-300 dark:text-slate-600`}>
32
+ {icon}
33
+ </div>
34
+ )}
35
+ <div className={`${s.heading} font-semibold text-slate-700 dark:text-slate-200`}>
36
+ {heading}
37
+ </div>
38
+ {body && (
39
+ <div className={`${s.body} max-w-sm text-slate-500 dark:text-slate-400`}>
40
+ {body}
41
+ </div>
42
+ )}
43
+ {action && <div className="mt-1">{action}</div>}
44
+ </div>
45
+ );
46
+ }