@hexclave/dashboard-ui-components 1.0.3 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/alert.js +4 -4
- package/dist/components/alert.js.map +1 -1
- package/dist/components/badge.js +1 -1
- package/dist/components/badge.js.map +1 -1
- package/dist/components/button.d.ts +4 -4
- package/dist/components/button.js +3 -3
- package/dist/components/button.js.map +1 -1
- package/dist/components/data-grid/data-grid-toolbar.js +5 -5
- package/dist/components/data-grid/data-grid-toolbar.js.map +1 -1
- package/dist/components/data-grid/data-grid.d.ts.map +1 -1
- package/dist/components/data-grid/data-grid.js +11 -5
- package/dist/components/data-grid/data-grid.js.map +1 -1
- package/dist/components/data-grid/data-grid.test.js +34 -1
- package/dist/components/data-grid/data-grid.test.js.map +1 -1
- package/dist/components/dialog.d.ts +6 -2
- package/dist/components/dialog.d.ts.map +1 -1
- package/dist/components/dialog.js +14 -10
- package/dist/components/dialog.js.map +1 -1
- package/dist/components/input.js +12 -9
- package/dist/components/input.js.map +1 -1
- package/dist/components/pill-toggle.js +3 -3
- package/dist/components/pill-toggle.js.map +1 -1
- package/dist/components/tabs.js +2 -2
- package/dist/components/tabs.js.map +1 -1
- package/dist/dashboard-ui-components.global.js +15639 -17400
- package/dist/dashboard-ui-components.global.js.map +4 -4
- package/dist/esm/components/alert.js +4 -4
- package/dist/esm/components/alert.js.map +1 -1
- package/dist/esm/components/badge.js +1 -1
- package/dist/esm/components/badge.js.map +1 -1
- package/dist/esm/components/button.d.ts +4 -4
- package/dist/esm/components/button.js +3 -3
- package/dist/esm/components/button.js.map +1 -1
- package/dist/esm/components/data-grid/data-grid-toolbar.js +5 -5
- package/dist/esm/components/data-grid/data-grid-toolbar.js.map +1 -1
- package/dist/esm/components/data-grid/data-grid.d.ts.map +1 -1
- package/dist/esm/components/data-grid/data-grid.js +11 -5
- package/dist/esm/components/data-grid/data-grid.js.map +1 -1
- package/dist/esm/components/data-grid/data-grid.test.js +34 -1
- package/dist/esm/components/data-grid/data-grid.test.js.map +1 -1
- package/dist/esm/components/dialog.d.ts +6 -2
- package/dist/esm/components/dialog.d.ts.map +1 -1
- package/dist/esm/components/dialog.js +13 -11
- package/dist/esm/components/dialog.js.map +1 -1
- package/dist/esm/components/input.js +12 -9
- package/dist/esm/components/input.js.map +1 -1
- package/dist/esm/components/pill-toggle.js +4 -4
- package/dist/esm/components/pill-toggle.js.map +1 -1
- package/dist/esm/components/tabs.js +2 -2
- package/dist/esm/components/tabs.js.map +1 -1
- package/dist/esm/index.d.ts +2 -2
- package/dist/esm/index.js +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +12 -0
- package/package.json +4 -3
- package/src/components/alert.tsx +120 -0
- package/src/components/analytics-chart/analytics-chart-pie.tsx +369 -0
- package/src/components/analytics-chart/analytics-chart.tsx +1585 -0
- package/src/components/analytics-chart/default-analytics-chart-tooltip.tsx +265 -0
- package/src/components/analytics-chart/format.ts +101 -0
- package/src/components/analytics-chart/index.ts +75 -0
- package/src/components/analytics-chart/palette.ts +68 -0
- package/src/components/analytics-chart/render-data-series.tsx +169 -0
- package/src/components/analytics-chart/state.ts +165 -0
- package/src/components/analytics-chart/strings.ts +72 -0
- package/src/components/analytics-chart/types.ts +220 -0
- package/src/components/badge.tsx +108 -0
- package/src/components/button.tsx +104 -0
- package/src/components/card.tsx +263 -0
- package/src/components/chart-card.tsx +101 -0
- package/src/components/chart-container.tsx +155 -0
- package/src/components/chart-legend.tsx +65 -0
- package/src/components/chart-theme.tsx +52 -0
- package/src/components/chart-tooltip.tsx +165 -0
- package/src/components/cursor-blast-effect.tsx +334 -0
- package/src/components/data-grid/data-grid-sizing.ts +51 -0
- package/src/components/data-grid/data-grid-toolbar.tsx +373 -0
- package/src/components/data-grid/data-grid.test.tsx +407 -0
- package/src/components/data-grid/data-grid.tsx +1231 -0
- package/src/components/data-grid/index.ts +64 -0
- package/src/components/data-grid/state.ts +235 -0
- package/src/components/data-grid/strings.ts +45 -0
- package/src/components/data-grid/types.ts +401 -0
- package/src/components/data-grid/use-data-source.ts +413 -0
- package/src/components/data-grid/use-url-state.test.tsx +88 -0
- package/src/components/data-grid/use-url-state.ts +298 -0
- package/src/components/dialog.tsx +218 -0
- package/src/components/edit-mode.tsx +17 -0
- package/src/components/empty-state.tsx +64 -0
- package/src/components/input.tsx +97 -0
- package/src/components/metric-card.tsx +142 -0
- package/src/components/pill-toggle.tsx +159 -0
- package/src/components/progress-bar.tsx +82 -0
- package/src/components/separator.tsx +36 -0
- package/src/components/skeleton.tsx +30 -0
- package/src/components/table.tsx +113 -0
- package/src/components/tabs.tsx +217 -0
- package/src/index.ts +71 -0
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useState, type ReactNode } from "react";
|
|
4
|
+
import { cn, Spinner } from "@hexclave/ui";
|
|
5
|
+
import { runAsynchronouslyWithAlert } from "@hexclave/shared/dist/utils/promises";
|
|
6
|
+
import { useGlassmorphicDefault } from "./card";
|
|
7
|
+
|
|
8
|
+
type DesignTabsSize = "sm" | "md";
|
|
9
|
+
type DesignTabsGradient = "blue" | "cyan" | "purple" | "green" | "orange" | "default";
|
|
10
|
+
|
|
11
|
+
export type DesignCategoryTabItem = {
|
|
12
|
+
id: string,
|
|
13
|
+
label: string,
|
|
14
|
+
count?: number,
|
|
15
|
+
badgeCount?: number,
|
|
16
|
+
icon?: React.ComponentType<React.SVGProps<SVGSVGElement>>,
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export type DesignCategoryTabsProps = Omit<React.ComponentProps<"div">, "onSelect"> & {
|
|
20
|
+
categories: DesignCategoryTabItem[],
|
|
21
|
+
selectedCategory: string,
|
|
22
|
+
onSelect: (id: string) => void | Promise<void>,
|
|
23
|
+
showBadge?: boolean,
|
|
24
|
+
size?: DesignTabsSize,
|
|
25
|
+
glassmorphic?: boolean,
|
|
26
|
+
gradient?: DesignTabsGradient,
|
|
27
|
+
/** Renders inside the tab bar after the tab buttons (not a tab). */
|
|
28
|
+
trailing?: ReactNode,
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
type TabSizeClass = {
|
|
32
|
+
button: string,
|
|
33
|
+
badge: string,
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
type GradientClass = {
|
|
37
|
+
activeText: string,
|
|
38
|
+
activeBadge: string,
|
|
39
|
+
underline: string,
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const tabSizeClasses = new Map<DesignTabsSize, TabSizeClass>([
|
|
43
|
+
["sm", { button: "px-3 py-2 text-xs", badge: "text-[10px] px-1.5 py-0.5" }],
|
|
44
|
+
["md", { button: "px-4 py-3 text-sm", badge: "text-xs px-1.5 py-0.5" }],
|
|
45
|
+
]);
|
|
46
|
+
|
|
47
|
+
const gradientClasses = new Map<DesignTabsGradient, GradientClass>([
|
|
48
|
+
[
|
|
49
|
+
"blue",
|
|
50
|
+
{
|
|
51
|
+
activeText: "text-blue-700 dark:text-blue-400",
|
|
52
|
+
activeBadge: "bg-blue-100 dark:bg-blue-900/30 text-blue-700 dark:text-blue-400",
|
|
53
|
+
underline: "bg-blue-700 dark:bg-blue-400",
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
|
+
[
|
|
57
|
+
"cyan",
|
|
58
|
+
{
|
|
59
|
+
activeText: "text-cyan-700 dark:text-cyan-300",
|
|
60
|
+
activeBadge: "bg-cyan-100 dark:bg-cyan-900/30 text-cyan-700 dark:text-cyan-300",
|
|
61
|
+
underline: "bg-cyan-600 dark:bg-cyan-400",
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
[
|
|
65
|
+
"purple",
|
|
66
|
+
{
|
|
67
|
+
activeText: "text-purple-700 dark:text-purple-300",
|
|
68
|
+
activeBadge: "bg-purple-100 dark:bg-purple-900/30 text-purple-700 dark:text-purple-300",
|
|
69
|
+
underline: "bg-purple-600 dark:bg-purple-400",
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
[
|
|
73
|
+
"green",
|
|
74
|
+
{
|
|
75
|
+
activeText: "text-emerald-700 dark:text-emerald-300",
|
|
76
|
+
activeBadge: "bg-emerald-100 dark:bg-emerald-900/30 text-emerald-700 dark:text-emerald-300",
|
|
77
|
+
underline: "bg-emerald-600 dark:bg-emerald-400",
|
|
78
|
+
},
|
|
79
|
+
],
|
|
80
|
+
[
|
|
81
|
+
"orange",
|
|
82
|
+
{
|
|
83
|
+
activeText: "text-amber-700 dark:text-amber-300",
|
|
84
|
+
activeBadge: "bg-amber-100 dark:bg-amber-900/30 text-amber-700 dark:text-amber-300",
|
|
85
|
+
underline: "bg-amber-600 dark:bg-amber-400",
|
|
86
|
+
},
|
|
87
|
+
],
|
|
88
|
+
[
|
|
89
|
+
"default",
|
|
90
|
+
{
|
|
91
|
+
activeText: "text-foreground",
|
|
92
|
+
activeBadge: "bg-foreground/10 text-foreground",
|
|
93
|
+
underline: "bg-foreground/80",
|
|
94
|
+
},
|
|
95
|
+
],
|
|
96
|
+
]);
|
|
97
|
+
|
|
98
|
+
function getMapValueOrThrow<TKey, TValue>(map: Map<TKey, TValue>, key: TKey, mapName: string) {
|
|
99
|
+
const value = map.get(key);
|
|
100
|
+
if (!value) {
|
|
101
|
+
throw new Error(`Missing ${mapName} entry for key "${String(key)}"`);
|
|
102
|
+
}
|
|
103
|
+
return value;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export function DesignCategoryTabs({
|
|
107
|
+
categories,
|
|
108
|
+
selectedCategory,
|
|
109
|
+
onSelect,
|
|
110
|
+
showBadge = true,
|
|
111
|
+
size = "sm",
|
|
112
|
+
glassmorphic: glassmorphicProp,
|
|
113
|
+
gradient = "blue",
|
|
114
|
+
trailing,
|
|
115
|
+
className,
|
|
116
|
+
...props
|
|
117
|
+
}: DesignCategoryTabsProps) {
|
|
118
|
+
const glassmorphic = useGlassmorphicDefault(glassmorphicProp);
|
|
119
|
+
const sizeClass = getMapValueOrThrow(tabSizeClasses, size, "tabSizeClasses");
|
|
120
|
+
const gradientClass = getMapValueOrThrow(gradientClasses, gradient, "gradientClasses");
|
|
121
|
+
const [loadingCategoryId, setLoadingCategoryId] = useState<string | null>(null);
|
|
122
|
+
|
|
123
|
+
const handleSelect = (categoryId: string) => {
|
|
124
|
+
const result = onSelect(categoryId);
|
|
125
|
+
if (result && typeof (result as Promise<void>).then === "function") {
|
|
126
|
+
setLoadingCategoryId(categoryId);
|
|
127
|
+
runAsynchronouslyWithAlert(
|
|
128
|
+
Promise.resolve(result).finally(() => setLoadingCategoryId(null))
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
return (
|
|
134
|
+
<div
|
|
135
|
+
className={cn(
|
|
136
|
+
"flex w-full min-w-0 items-center gap-2",
|
|
137
|
+
glassmorphic
|
|
138
|
+
? "rounded-xl bg-zinc-100/90 p-1 ring-1 ring-black/[0.06] backdrop-blur-sm dark:bg-white/[0.04] dark:ring-white/[0.06]"
|
|
139
|
+
: "border-b border-gray-300 dark:border-gray-800",
|
|
140
|
+
className
|
|
141
|
+
)}
|
|
142
|
+
{...props}
|
|
143
|
+
>
|
|
144
|
+
<div
|
|
145
|
+
className={cn(
|
|
146
|
+
"flex min-h-0 min-w-0 items-center gap-1 overflow-x-auto flex-nowrap [&::-webkit-scrollbar]:hidden",
|
|
147
|
+
)}
|
|
148
|
+
>
|
|
149
|
+
{categories.map((category) => {
|
|
150
|
+
const isActive = selectedCategory === category.id;
|
|
151
|
+
const badgeValue = category.badgeCount ?? category.count;
|
|
152
|
+
const shouldShowBadge = showBadge && badgeValue !== undefined;
|
|
153
|
+
|
|
154
|
+
return (
|
|
155
|
+
<button
|
|
156
|
+
key={category.id}
|
|
157
|
+
onClick={() => handleSelect(category.id)}
|
|
158
|
+
disabled={loadingCategoryId !== null}
|
|
159
|
+
className={cn(
|
|
160
|
+
"font-medium transition-all duration-150 hover:transition-none relative flex flex-shrink-0 items-center justify-center gap-2 whitespace-nowrap",
|
|
161
|
+
"hover:text-gray-900 dark:hover:text-gray-100",
|
|
162
|
+
sizeClass.button,
|
|
163
|
+
glassmorphic ? "rounded-lg" : "",
|
|
164
|
+
isActive
|
|
165
|
+
? cn(
|
|
166
|
+
gradientClass.activeText,
|
|
167
|
+
glassmorphic && "bg-white shadow-sm ring-1 ring-black/[0.12] dark:bg-background dark:ring-white/[0.06]"
|
|
168
|
+
)
|
|
169
|
+
: cn(
|
|
170
|
+
"text-gray-700 dark:text-gray-400",
|
|
171
|
+
glassmorphic && "rounded-lg hover:bg-white/50 dark:hover:bg-white/[0.06]",
|
|
172
|
+
)
|
|
173
|
+
)}
|
|
174
|
+
>
|
|
175
|
+
{loadingCategoryId === category.id && (
|
|
176
|
+
<Spinner
|
|
177
|
+
size={12}
|
|
178
|
+
className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 pointer-events-none"
|
|
179
|
+
/>
|
|
180
|
+
)}
|
|
181
|
+
<span className={cn(
|
|
182
|
+
"flex items-center gap-2",
|
|
183
|
+
loadingCategoryId === category.id && "invisible"
|
|
184
|
+
)}>
|
|
185
|
+
{category.icon && (
|
|
186
|
+
<category.icon className="h-4 w-4 shrink-0" aria-hidden />
|
|
187
|
+
)}
|
|
188
|
+
{category.label}
|
|
189
|
+
{shouldShowBadge && (
|
|
190
|
+
<span
|
|
191
|
+
className={cn(
|
|
192
|
+
"rounded-full",
|
|
193
|
+
sizeClass.badge,
|
|
194
|
+
isActive
|
|
195
|
+
? gradientClass.activeBadge
|
|
196
|
+
: "bg-gray-200 dark:bg-gray-800 text-gray-600 dark:text-gray-400"
|
|
197
|
+
)}
|
|
198
|
+
>
|
|
199
|
+
{badgeValue}
|
|
200
|
+
</span>
|
|
201
|
+
)}
|
|
202
|
+
</span>
|
|
203
|
+
{!glassmorphic && isActive && (
|
|
204
|
+
<div className={cn("absolute bottom-0 left-0 right-0 h-0.5", gradientClass.underline)} />
|
|
205
|
+
)}
|
|
206
|
+
</button>
|
|
207
|
+
);
|
|
208
|
+
})}
|
|
209
|
+
</div>
|
|
210
|
+
{trailing != null ? (
|
|
211
|
+
<div className="flex shrink-0 items-center">
|
|
212
|
+
{trailing}
|
|
213
|
+
</div>
|
|
214
|
+
) : null}
|
|
215
|
+
</div>
|
|
216
|
+
);
|
|
217
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
export { DesignAlert } from "./components/alert";
|
|
2
|
+
export type { DesignAlertProps } from "./components/alert";
|
|
3
|
+
|
|
4
|
+
export { DesignBadge } from "./components/badge";
|
|
5
|
+
export type { DesignBadgeColor, DesignBadgeSize, DesignBadgeContentMode, DesignBadgeProps } from "./components/badge";
|
|
6
|
+
|
|
7
|
+
export { DesignButton } from "./components/button";
|
|
8
|
+
export type { DesignOriginalButtonProps, DesignButtonProps } from "./components/button";
|
|
9
|
+
|
|
10
|
+
export { DesignCard, DesignCardTint, useInsideDesignCard, useGlassmorphicDefault } from "./components/card";
|
|
11
|
+
export type { DesignCardProps, DesignCardTintProps } from "./components/card";
|
|
12
|
+
|
|
13
|
+
export { CursorBlastEffect } from "./components/cursor-blast-effect";
|
|
14
|
+
export type { CursorBlastEffectProps } from "./components/cursor-blast-effect";
|
|
15
|
+
|
|
16
|
+
export {
|
|
17
|
+
DesignDialog,
|
|
18
|
+
DesignDialogClose,
|
|
19
|
+
DesignDialogDescription,
|
|
20
|
+
DesignDialogRoot,
|
|
21
|
+
DesignDialogTitle,
|
|
22
|
+
DesignDialogTrigger,
|
|
23
|
+
designDialogGlassmorphicOverlayClass,
|
|
24
|
+
designDialogGlassmorphicSurfaceClass,
|
|
25
|
+
} from "./components/dialog";
|
|
26
|
+
export type { DesignDialogProps, DesignDialogSize, DesignDialogVariant } from "./components/dialog";
|
|
27
|
+
|
|
28
|
+
export { DesignEditMode, useDesignEditMode } from "./components/edit-mode";
|
|
29
|
+
|
|
30
|
+
export { DesignInput } from "./components/input";
|
|
31
|
+
export type { DesignInputProps } from "./components/input";
|
|
32
|
+
|
|
33
|
+
export { DesignPillToggle } from "./components/pill-toggle";
|
|
34
|
+
export type { DesignPillToggleOption, DesignPillToggleProps } from "./components/pill-toggle";
|
|
35
|
+
|
|
36
|
+
export { DesignSeparator } from "./components/separator";
|
|
37
|
+
export type { DesignSeparatorProps } from "./components/separator";
|
|
38
|
+
|
|
39
|
+
export { DesignSkeleton } from "./components/skeleton";
|
|
40
|
+
export type { DesignSkeletonProps } from "./components/skeleton";
|
|
41
|
+
|
|
42
|
+
export { DesignTable, DesignTableHeader, DesignTableBody, DesignTableRow, DesignTableHead, DesignTableCell } from "./components/table";
|
|
43
|
+
|
|
44
|
+
export { DesignCategoryTabs } from "./components/tabs";
|
|
45
|
+
export type { DesignCategoryTabItem, DesignCategoryTabsProps } from "./components/tabs";
|
|
46
|
+
|
|
47
|
+
export { DESIGN_CHART_COLORS, getDesignChartColor, DESIGN_CHART_GRID_COLOR, DESIGN_CHART_AXIS_TICK_STYLE } from "./components/chart-theme";
|
|
48
|
+
export type { DesignChartColorEntry, DesignChartColorName } from "./components/chart-theme";
|
|
49
|
+
|
|
50
|
+
export { DesignChartContainer, DesignChartStyle, useDesignChart, getPayloadConfigFromPayload } from "./components/chart-container";
|
|
51
|
+
export type { DesignChartConfig } from "./components/chart-container";
|
|
52
|
+
|
|
53
|
+
export { DesignChartTooltip, DesignChartTooltipContent } from "./components/chart-tooltip";
|
|
54
|
+
|
|
55
|
+
export { DesignChartLegendContent } from "./components/chart-legend";
|
|
56
|
+
|
|
57
|
+
export { DesignChartCard } from "./components/chart-card";
|
|
58
|
+
export type { DesignChartCardProps } from "./components/chart-card";
|
|
59
|
+
|
|
60
|
+
export { DesignMetricCard } from "./components/metric-card";
|
|
61
|
+
export type { DesignMetricCardProps, DesignMetricCardTrend } from "./components/metric-card";
|
|
62
|
+
|
|
63
|
+
export { DesignProgressBar } from "./components/progress-bar";
|
|
64
|
+
export type { DesignProgressBarProps } from "./components/progress-bar";
|
|
65
|
+
|
|
66
|
+
export { DesignEmptyState } from "./components/empty-state";
|
|
67
|
+
export type { DesignEmptyStateProps } from "./components/empty-state";
|
|
68
|
+
|
|
69
|
+
export * from "./components/analytics-chart";
|
|
70
|
+
|
|
71
|
+
export * from "./components/data-grid";
|