@thangnqdev/ui 0.1.1 → 0.2.0
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/LICENSE +21 -0
- package/README.md +86 -65
- package/dist/bento/index.cjs.map +1 -1
- package/dist/bento/index.js +2 -2
- package/dist/bento/styles.css +2 -46
- package/dist/buttons/index.cjs +111 -18
- package/dist/buttons/index.cjs.map +1 -1
- package/dist/buttons/index.d.cts +1 -1
- package/dist/buttons/index.d.ts +1 -1
- package/dist/buttons/index.js +3 -3
- package/dist/buttons/styles.css +2 -6
- package/dist/{chunk-4S6L5V7X.js → chunk-2YJBW4E2.js} +2 -2
- package/dist/chunk-2YJBW4E2.js.map +1 -0
- package/dist/{chunk-F5Q7BTMH.js → chunk-4CRFNALF.js} +1011 -556
- package/dist/chunk-4CRFNALF.js.map +1 -0
- package/dist/{chunk-LWFRUJRU.js → chunk-4MS6ZHFQ.js} +225 -41
- package/dist/chunk-4MS6ZHFQ.js.map +1 -0
- package/dist/{chunk-2OXZK6IP.js → chunk-77KTYOMQ.js} +3 -3
- package/dist/chunk-77KTYOMQ.js.map +1 -0
- package/dist/{chunk-IABPUCAQ.js → chunk-ADO3SVUA.js} +2 -2
- package/dist/chunk-ADO3SVUA.js.map +1 -0
- package/dist/{chunk-GXI2H5XA.js → chunk-D7FB3TCA.js} +3 -3
- package/dist/chunk-D7FB3TCA.js.map +1 -0
- package/dist/chunk-DSEL7ELZ.js +314 -0
- package/dist/chunk-DSEL7ELZ.js.map +1 -0
- package/dist/{chunk-KJRBRTQE.js → chunk-EXFR2BFJ.js} +37 -28
- package/dist/chunk-EXFR2BFJ.js.map +1 -0
- package/dist/{chunk-PF4ZHGVW.js → chunk-GXWB6BSY.js} +116 -23
- package/dist/chunk-GXWB6BSY.js.map +1 -0
- package/dist/{chunk-66VWUJEI.js → chunk-I2FQBMVW.js} +3 -3
- package/dist/chunk-I2FQBMVW.js.map +1 -0
- package/dist/{chunk-EU2LPUYP.js → chunk-I5O2WCGF.js} +3 -3
- package/dist/chunk-I5O2WCGF.js.map +1 -0
- package/dist/{chunk-ATYGDTMK.js → chunk-ME4XILG5.js} +5 -5
- package/dist/chunk-ME4XILG5.js.map +1 -0
- package/dist/{chunk-5FZ6ZFII.js → chunk-PC5SZFZC.js} +373 -150
- package/dist/chunk-PC5SZFZC.js.map +1 -0
- package/dist/{chunk-C4SUXMI3.js → chunk-S6XJMYME.js} +3 -3
- package/dist/chunk-S6XJMYME.js.map +1 -0
- package/dist/{chunk-A7P3O5Z5.js → chunk-V52JOSDF.js} +3 -3
- package/dist/chunk-V52JOSDF.js.map +1 -0
- package/dist/{chunk-NFVONJUK.js → chunk-W5WNWTQC.js} +455 -211
- package/dist/chunk-W5WNWTQC.js.map +1 -0
- package/dist/{chunk-WAFHC4DQ.js → chunk-YJ64RI7J.js} +3 -3
- package/dist/chunk-YJ64RI7J.js.map +1 -0
- package/dist/chunk-YOCGBORV.js +155 -0
- package/dist/chunk-YOCGBORV.js.map +1 -0
- package/dist/chunk-ZEDXARXW.js +96 -0
- package/dist/chunk-ZEDXARXW.js.map +1 -0
- package/dist/components.css +2 -0
- package/dist/core/index.cjs +33 -24
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.js +2 -2
- package/dist/core/styles.css +2 -130
- package/dist/data-display/index.cjs +770 -247
- package/dist/data-display/index.cjs.map +1 -1
- package/dist/data-display/index.d.cts +1 -1
- package/dist/data-display/index.d.ts +1 -1
- package/dist/data-display/index.js +5 -4
- package/dist/data-display/styles.css +2 -4
- package/dist/feedback/index.cjs.map +1 -1
- package/dist/feedback/index.js +2 -2
- package/dist/feedback/styles.css +2 -4
- package/dist/forms/index.cjs +1211 -459
- package/dist/forms/index.cjs.map +1 -1
- package/dist/forms/index.d.cts +1 -1
- package/dist/forms/index.d.ts +1 -1
- package/dist/forms/index.js +8 -8
- package/dist/forms/styles.css +2 -6
- package/dist/glass/index.cjs.map +1 -1
- package/dist/glass/index.js +2 -2
- package/dist/glass/styles.css +2 -81
- package/dist/{index-D6fE7w-b.d.cts → index-BGt_hecO.d.cts} +1 -0
- package/dist/{index-D6fE7w-b.d.ts → index-BGt_hecO.d.ts} +1 -0
- package/dist/{index-DzcWh1Hs.d.cts → index-BtDvpZCf.d.cts} +7 -0
- package/dist/{index-DzcWh1Hs.d.ts → index-BtDvpZCf.d.ts} +7 -0
- package/dist/{index-Cle6QzQl.d.ts → index-COX1sBUN.d.ts} +27 -3
- package/dist/{index-BkRqGNG1.d.ts → index-Cg8MuP7u.d.cts} +40 -13
- package/dist/{index-BkRqGNG1.d.cts → index-Cg8MuP7u.d.ts} +40 -13
- package/dist/{index-CenuF_P2.d.ts → index-DHkPRTvE.d.cts} +39 -8
- package/dist/{index-CenuF_P2.d.cts → index-DHkPRTvE.d.ts} +39 -8
- package/dist/{index-TyK-Ldpy.d.cts → index-Du_oht9k.d.cts} +27 -3
- package/dist/index.cjs +2481 -917
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.js +19 -19
- package/dist/layout/index.cjs.map +1 -1
- package/dist/layout/index.js +2 -2
- package/dist/layout/styles.css +2 -8
- package/dist/navigation/index.cjs +288 -48
- package/dist/navigation/index.cjs.map +1 -1
- package/dist/navigation/index.d.cts +1 -1
- package/dist/navigation/index.d.ts +1 -1
- package/dist/navigation/index.js +6 -6
- package/dist/navigation/styles.css +2 -4
- package/dist/overlays/index.cjs +566 -229
- package/dist/overlays/index.cjs.map +1 -1
- package/dist/overlays/index.d.cts +1 -1
- package/dist/overlays/index.d.ts +1 -1
- package/dist/overlays/index.js +7 -7
- package/dist/overlays/styles.css +2 -8
- package/dist/reset.css +45 -0
- package/dist/styles.css +1 -1
- package/dist/tokens.css +11 -0
- package/dist/typography/index.cjs.map +1 -1
- package/dist/typography/index.js +4 -4
- package/dist/typography/styles.css +2 -5
- package/llms.txt +211 -113
- package/package.json +160 -116
- package/src/bento/BentoCard.tsx +140 -140
- package/src/bento/BentoGrid.tsx +50 -50
- package/src/bento/index.ts +2 -2
- package/src/bento/tokens.css +46 -46
- package/src/buttons/Button.tsx +104 -104
- package/src/buttons/ButtonGroup.tsx +43 -43
- package/src/buttons/IconButton.tsx +79 -79
- package/src/buttons/SplitButton.tsx +186 -86
- package/src/buttons/ToggleButton.tsx +157 -157
- package/src/buttons/index.ts +5 -5
- package/src/buttons/tokens.css +6 -6
- package/src/core/ThemeProvider.tsx +135 -123
- package/src/core/index.ts +2 -2
- package/src/core/tokens.css +134 -130
- package/src/data-display/Accordion.tsx +147 -147
- package/src/data-display/Avatar.tsx +134 -134
- package/src/data-display/Card.tsx +112 -112
- package/src/data-display/Chip.tsx +74 -74
- package/src/data-display/DataTablePro.tsx +299 -121
- package/src/data-display/StatCard.tsx +60 -60
- package/src/data-display/Table.tsx +74 -74
- package/src/data-display/Timeline.tsx +62 -62
- package/src/data-display/TreeView.tsx +243 -104
- package/src/data-display/tokens.css +4 -4
- package/src/feedback/Alert.tsx +80 -80
- package/src/feedback/EmptyState.tsx +45 -45
- package/src/feedback/Skeleton.tsx +66 -66
- package/src/feedback/Spinner.tsx +65 -65
- package/src/feedback/index.ts +5 -5
- package/src/feedback/tokens.css +4 -4
- package/src/forms/Checkbox.tsx +149 -69
- package/src/forms/CheckboxGroup.tsx +76 -29
- package/src/forms/Combobox.tsx +172 -28
- package/src/forms/DatePicker.tsx +385 -81
- package/src/forms/FileUpload.tsx +51 -7
- package/src/forms/FormField.tsx +115 -115
- package/src/forms/Input.tsx +151 -151
- package/src/forms/NumberInput.tsx +34 -20
- package/src/forms/PasswordInput.tsx +35 -35
- package/src/forms/PinInput.tsx +139 -125
- package/src/forms/Radio.tsx +142 -142
- package/src/forms/RangeSlider.tsx +237 -111
- package/src/forms/SearchInput.tsx +34 -34
- package/src/forms/Select.tsx +103 -103
- package/src/forms/Slider.tsx +85 -85
- package/src/forms/Textarea.tsx +114 -114
- package/src/forms/tokens.css +6 -6
- package/src/glass/GlassButton.tsx +59 -59
- package/src/glass/GlassCard.tsx +71 -71
- package/src/glass/index.ts +3 -3
- package/src/glass/tokens.css +81 -81
- package/src/index.ts +26 -26
- package/src/layout/AspectRatio.tsx +39 -39
- package/src/layout/Container.tsx +53 -53
- package/src/layout/Divider.tsx +61 -61
- package/src/layout/Flex.tsx +79 -79
- package/src/layout/Grid.tsx +124 -124
- package/src/layout/PageLayout.tsx +59 -59
- package/src/layout/Section.tsx +47 -47
- package/src/layout/Spacer.tsx +30 -30
- package/src/layout/Stack.tsx +88 -88
- package/src/layout/tokens.css +8 -8
- package/src/navigation/Breadcrumb.tsx +73 -73
- package/src/navigation/CommandPalette.tsx +142 -142
- package/src/navigation/DropdownMenu.tsx +244 -160
- package/src/navigation/Pagination.tsx +114 -114
- package/src/navigation/Stepper.tsx +93 -93
- package/src/navigation/Tabs.tsx +265 -133
- package/src/navigation/index.ts +6 -6
- package/src/navigation/tokens.css +4 -4
- package/src/overlays/AlertDialog.tsx +63 -54
- package/src/overlays/BottomSheet.tsx +30 -10
- package/src/overlays/ContextMenu.tsx +51 -9
- package/src/overlays/Drawer.tsx +160 -145
- package/src/overlays/FocusTrap.tsx +122 -49
- package/src/overlays/Modal.tsx +296 -219
- package/src/overlays/Popover.tsx +55 -25
- package/src/overlays/Portal.tsx +23 -23
- package/src/overlays/Toast.tsx +175 -137
- package/src/overlays/Tooltip.tsx +125 -100
- package/src/overlays/tokens.css +8 -8
- package/src/registry/components.ts +1368 -0
- package/src/styles/components.css +39 -0
- package/src/styles/index.css +2 -93
- package/src/styles/reset.css +45 -0
- package/src/styles/tokens.css +11 -2
- package/src/typography/Blockquote.tsx +32 -32
- package/src/typography/Code.tsx +89 -89
- package/src/typography/Heading.tsx +56 -56
- package/src/typography/Kbd.tsx +25 -25
- package/src/typography/Label.tsx +47 -47
- package/src/typography/Link.tsx +56 -56
- package/src/typography/Text.tsx +62 -62
- package/src/typography/index.ts +7 -7
- package/src/typography/tokens.css +5 -5
- package/src/utils/cn.ts +6 -6
- package/src/utils/scroll-lock.ts +19 -0
- package/src/utils/useControllableState.ts +54 -0
- package/ui-contract.json +192 -35
- package/dist/chunk-2OXZK6IP.js.map +0 -1
- package/dist/chunk-4S6L5V7X.js.map +0 -1
- package/dist/chunk-5FZ6ZFII.js.map +0 -1
- package/dist/chunk-66VWUJEI.js.map +0 -1
- package/dist/chunk-A7P3O5Z5.js.map +0 -1
- package/dist/chunk-ATYGDTMK.js.map +0 -1
- package/dist/chunk-C4SUXMI3.js.map +0 -1
- package/dist/chunk-EU2LPUYP.js.map +0 -1
- package/dist/chunk-F5Q7BTMH.js.map +0 -1
- package/dist/chunk-GXI2H5XA.js.map +0 -1
- package/dist/chunk-H3LCNPMC.js +0 -101
- package/dist/chunk-H3LCNPMC.js.map +0 -1
- package/dist/chunk-IABPUCAQ.js.map +0 -1
- package/dist/chunk-KJRBRTQE.js.map +0 -1
- package/dist/chunk-LBUBXUYQ.js +0 -40
- package/dist/chunk-LBUBXUYQ.js.map +0 -1
- package/dist/chunk-LWFRUJRU.js.map +0 -1
- package/dist/chunk-NFVONJUK.js.map +0 -1
- package/dist/chunk-PF4ZHGVW.js.map +0 -1
- package/dist/chunk-WAFHC4DQ.js.map +0 -1
- package/dist/chunk-X76KBH4Y.js +0 -71
- package/dist/chunk-X76KBH4Y.js.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var React15 = require('react');
|
|
4
4
|
var classVarianceAuthority = require('class-variance-authority');
|
|
5
5
|
var clsx = require('clsx');
|
|
6
6
|
var tailwindMerge = require('tailwind-merge');
|
|
@@ -9,7 +9,7 @@ var lucideReact = require('lucide-react');
|
|
|
9
9
|
|
|
10
10
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
11
11
|
|
|
12
|
-
var
|
|
12
|
+
var React15__default = /*#__PURE__*/_interopDefault(React15);
|
|
13
13
|
|
|
14
14
|
// src/data-display/Card.tsx
|
|
15
15
|
function cn(...inputs) {
|
|
@@ -44,7 +44,7 @@ var cardVariants = classVarianceAuthority.cva(
|
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
);
|
|
47
|
-
var Card =
|
|
47
|
+
var Card = React15.forwardRef(
|
|
48
48
|
({ className, variant, padding, specular = true, children, ...props }, ref) => {
|
|
49
49
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
50
50
|
"div",
|
|
@@ -58,53 +58,53 @@ var Card = React11.forwardRef(
|
|
|
58
58
|
}
|
|
59
59
|
);
|
|
60
60
|
Card.displayName = "Card";
|
|
61
|
-
var CardHeader =
|
|
61
|
+
var CardHeader = React15.forwardRef(
|
|
62
62
|
({ className, children, ...props }, ref) => {
|
|
63
63
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("flex flex-col space-y-1.5 mb-5", className), ...props, children });
|
|
64
64
|
}
|
|
65
65
|
);
|
|
66
66
|
CardHeader.displayName = "CardHeader";
|
|
67
|
-
var CardTitle =
|
|
67
|
+
var CardTitle = React15.forwardRef(
|
|
68
68
|
({ className, children, ...props }, ref) => {
|
|
69
69
|
return /* @__PURE__ */ jsxRuntime.jsx("h3", { ref, className: cn("text-lg sm:text-xl font-bold tracking-tight text-[var(--ui-text-primary)]", className), ...props, children });
|
|
70
70
|
}
|
|
71
71
|
);
|
|
72
72
|
CardTitle.displayName = "CardTitle";
|
|
73
|
-
var CardDescription =
|
|
73
|
+
var CardDescription = React15.forwardRef(
|
|
74
74
|
({ className, children, ...props }, ref) => {
|
|
75
75
|
return /* @__PURE__ */ jsxRuntime.jsx("p", { ref, className: cn("text-xs sm:text-sm text-[var(--ui-text-muted)] font-normal leading-relaxed", className), ...props, children });
|
|
76
76
|
}
|
|
77
77
|
);
|
|
78
78
|
CardDescription.displayName = "CardDescription";
|
|
79
|
-
var CardContent =
|
|
79
|
+
var CardContent = React15.forwardRef(
|
|
80
80
|
({ className, children, ...props }, ref) => {
|
|
81
81
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("pt-0", className), ...props, children });
|
|
82
82
|
}
|
|
83
83
|
);
|
|
84
84
|
CardContent.displayName = "CardContent";
|
|
85
|
-
var CardFooter =
|
|
85
|
+
var CardFooter = React15.forwardRef(
|
|
86
86
|
({ className, children, ...props }, ref) => {
|
|
87
87
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("flex items-center pt-4 mt-5 border-t border-[var(--ui-border-subtle)]", className), ...props, children });
|
|
88
88
|
}
|
|
89
89
|
);
|
|
90
90
|
CardFooter.displayName = "CardFooter";
|
|
91
|
-
var Table =
|
|
91
|
+
var Table = React15.forwardRef(
|
|
92
92
|
({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative w-full overflow-auto rounded-[var(--ui-radius-lg)] border border-[var(--ui-border-default)] bg-[var(--ui-bg-surface)]", children: /* @__PURE__ */ jsxRuntime.jsx("table", { ref, className: cn("w-full caption-bottom text-sm text-left", className), ...props }) })
|
|
93
93
|
);
|
|
94
94
|
Table.displayName = "Table";
|
|
95
|
-
var TableHeader =
|
|
95
|
+
var TableHeader = React15.forwardRef(
|
|
96
96
|
({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("thead", { ref, className: cn("bg-[var(--ui-bg-secondary)] border-b border-[var(--ui-border-default)]", className), ...props })
|
|
97
97
|
);
|
|
98
98
|
TableHeader.displayName = "TableHeader";
|
|
99
|
-
var TableBody =
|
|
99
|
+
var TableBody = React15.forwardRef(
|
|
100
100
|
({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("tbody", { ref, className: cn("[&_tr:last-child]:border-0", className), ...props })
|
|
101
101
|
);
|
|
102
102
|
TableBody.displayName = "TableBody";
|
|
103
|
-
var TableFooter =
|
|
103
|
+
var TableFooter = React15.forwardRef(
|
|
104
104
|
({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("tfoot", { ref, className: cn("bg-[var(--ui-bg-secondary)] font-medium border-t border-[var(--ui-border-default)]", className), ...props })
|
|
105
105
|
);
|
|
106
106
|
TableFooter.displayName = "TableFooter";
|
|
107
|
-
var TableRow =
|
|
107
|
+
var TableRow = React15.forwardRef(
|
|
108
108
|
({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
109
109
|
"tr",
|
|
110
110
|
{
|
|
@@ -118,7 +118,7 @@ var TableRow = React11.forwardRef(
|
|
|
118
118
|
)
|
|
119
119
|
);
|
|
120
120
|
TableRow.displayName = "TableRow";
|
|
121
|
-
var TableHead =
|
|
121
|
+
var TableHead = React15.forwardRef(
|
|
122
122
|
({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
123
123
|
"th",
|
|
124
124
|
{
|
|
@@ -132,11 +132,11 @@ var TableHead = React11.forwardRef(
|
|
|
132
132
|
)
|
|
133
133
|
);
|
|
134
134
|
TableHead.displayName = "TableHead";
|
|
135
|
-
var TableCell =
|
|
135
|
+
var TableCell = React15.forwardRef(
|
|
136
136
|
({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("td", { ref, className: cn("p-4 align-middle text-sm text-[var(--ui-text-primary)]", className), ...props })
|
|
137
137
|
);
|
|
138
138
|
TableCell.displayName = "TableCell";
|
|
139
|
-
var TableCaption =
|
|
139
|
+
var TableCaption = React15.forwardRef(
|
|
140
140
|
({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("caption", { ref, className: cn("mt-4 text-xs text-[var(--ui-text-muted)]", className), ...props })
|
|
141
141
|
);
|
|
142
142
|
TableCaption.displayName = "TableCaption";
|
|
@@ -181,9 +181,9 @@ var statusVariants = classVarianceAuthority.cva(
|
|
|
181
181
|
}
|
|
182
182
|
}
|
|
183
183
|
);
|
|
184
|
-
var Avatar =
|
|
184
|
+
var Avatar = React15.forwardRef(
|
|
185
185
|
({ className, size = "md", src, alt, name, status, children, ...props }, ref) => {
|
|
186
|
-
const [hasError, setHasError] =
|
|
186
|
+
const [hasError, setHasError] = React15.useState(false);
|
|
187
187
|
const getInitials = (n) => {
|
|
188
188
|
if (!n) return "";
|
|
189
189
|
const parts = n.trim().split(" ");
|
|
@@ -212,9 +212,9 @@ var Avatar = React11.forwardRef(
|
|
|
212
212
|
}
|
|
213
213
|
);
|
|
214
214
|
Avatar.displayName = "Avatar";
|
|
215
|
-
var AvatarGroup =
|
|
215
|
+
var AvatarGroup = React15.forwardRef(
|
|
216
216
|
({ className, max = 4, spacing = "tight", children, ...props }, ref) => {
|
|
217
|
-
const childArray =
|
|
217
|
+
const childArray = React15__default.default.Children.toArray(children);
|
|
218
218
|
const visibleChildren = childArray.slice(0, max);
|
|
219
219
|
const remainingCount = childArray.length - max;
|
|
220
220
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -240,13 +240,13 @@ var AvatarGroup = React11.forwardRef(
|
|
|
240
240
|
}
|
|
241
241
|
);
|
|
242
242
|
AvatarGroup.displayName = "AvatarGroup";
|
|
243
|
-
var AccordionContext =
|
|
243
|
+
var AccordionContext = React15.createContext(null);
|
|
244
244
|
function useAccordion() {
|
|
245
|
-
const context =
|
|
245
|
+
const context = React15.useContext(AccordionContext);
|
|
246
246
|
if (!context) throw new Error("AccordionItem components must be used within <Accordion />");
|
|
247
247
|
return context;
|
|
248
248
|
}
|
|
249
|
-
var Accordion =
|
|
249
|
+
var Accordion = React15.forwardRef(
|
|
250
250
|
({
|
|
251
251
|
className,
|
|
252
252
|
type = "single",
|
|
@@ -256,7 +256,7 @@ var Accordion = React11.forwardRef(
|
|
|
256
256
|
children,
|
|
257
257
|
...props
|
|
258
258
|
}, ref) => {
|
|
259
|
-
const [internalOpen, setInternalOpen] =
|
|
259
|
+
const [internalOpen, setInternalOpen] = React15.useState(() => {
|
|
260
260
|
if (Array.isArray(defaultValue)) return defaultValue;
|
|
261
261
|
if (typeof defaultValue === "string") return [defaultValue];
|
|
262
262
|
return [];
|
|
@@ -276,17 +276,17 @@ var Accordion = React11.forwardRef(
|
|
|
276
276
|
}
|
|
277
277
|
);
|
|
278
278
|
Accordion.displayName = "Accordion";
|
|
279
|
-
var AccordionItemContext =
|
|
280
|
-
var AccordionItem =
|
|
279
|
+
var AccordionItemContext = React15.createContext(null);
|
|
280
|
+
var AccordionItem = React15.forwardRef(
|
|
281
281
|
({ className, value, children, ...props }, ref) => {
|
|
282
282
|
return /* @__PURE__ */ jsxRuntime.jsx(AccordionItemContext.Provider, { value: { id: value }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("w-full", className), ...props, children }) });
|
|
283
283
|
}
|
|
284
284
|
);
|
|
285
285
|
AccordionItem.displayName = "AccordionItem";
|
|
286
|
-
var AccordionTrigger =
|
|
286
|
+
var AccordionTrigger = React15.forwardRef(
|
|
287
287
|
({ className, children, ...props }, ref) => {
|
|
288
288
|
const { openItems, toggleItem } = useAccordion();
|
|
289
|
-
const item =
|
|
289
|
+
const item = React15.useContext(AccordionItemContext);
|
|
290
290
|
const isOpen = item ? openItems.includes(item.id) : false;
|
|
291
291
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
292
292
|
"button",
|
|
@@ -317,10 +317,10 @@ var AccordionTrigger = React11.forwardRef(
|
|
|
317
317
|
}
|
|
318
318
|
);
|
|
319
319
|
AccordionTrigger.displayName = "AccordionTrigger";
|
|
320
|
-
var AccordionContent =
|
|
320
|
+
var AccordionContent = React15.forwardRef(
|
|
321
321
|
({ className, children, ...props }, ref) => {
|
|
322
322
|
const { openItems } = useAccordion();
|
|
323
|
-
const item =
|
|
323
|
+
const item = React15.useContext(AccordionItemContext);
|
|
324
324
|
const isOpen = item ? openItems.includes(item.id) : false;
|
|
325
325
|
if (!isOpen) return null;
|
|
326
326
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -364,7 +364,7 @@ var chipVariants = classVarianceAuthority.cva(
|
|
|
364
364
|
}
|
|
365
365
|
}
|
|
366
366
|
);
|
|
367
|
-
var Chip =
|
|
367
|
+
var Chip = React15.forwardRef(
|
|
368
368
|
({ className, variant, size, clickable, onRemove, icon, children, onClick, ...props }, ref) => {
|
|
369
369
|
const isClickable = Boolean(clickable || onClick);
|
|
370
370
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -396,7 +396,7 @@ var Chip = React11.forwardRef(
|
|
|
396
396
|
}
|
|
397
397
|
);
|
|
398
398
|
Chip.displayName = "Chip";
|
|
399
|
-
var StatCard =
|
|
399
|
+
var StatCard = React15.forwardRef(
|
|
400
400
|
({ className, label, value, change, trend, trendLabel, icon, ...props }, ref) => {
|
|
401
401
|
return /* @__PURE__ */ jsxRuntime.jsxs(Card, { ref, className: cn("p-6", className), ...props, children: [
|
|
402
402
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
@@ -428,7 +428,7 @@ var StatCard = React11.forwardRef(
|
|
|
428
428
|
}
|
|
429
429
|
);
|
|
430
430
|
StatCard.displayName = "StatCard";
|
|
431
|
-
var Timeline =
|
|
431
|
+
var Timeline = React15.forwardRef(
|
|
432
432
|
({ className, items, ...props }, ref) => {
|
|
433
433
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, className: cn("relative pl-6 space-y-6", className), ...props, children: [
|
|
434
434
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute left-[11px] top-2 bottom-2 w-0.5 bg-[var(--ui-border-subtle)]" }),
|
|
@@ -493,7 +493,7 @@ var buttonVariants = classVarianceAuthority.cva(
|
|
|
493
493
|
}
|
|
494
494
|
}
|
|
495
495
|
);
|
|
496
|
-
var Button =
|
|
496
|
+
var Button = React15.forwardRef(
|
|
497
497
|
({
|
|
498
498
|
className,
|
|
499
499
|
variant,
|
|
@@ -537,6 +537,285 @@ var Button = React11.forwardRef(
|
|
|
537
537
|
}
|
|
538
538
|
);
|
|
539
539
|
Button.displayName = "Button";
|
|
540
|
+
var labelVariants = classVarianceAuthority.cva(
|
|
541
|
+
"text-sm font-medium leading-none select-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 text-[var(--ui-text-primary)] inline-flex items-center gap-1",
|
|
542
|
+
{
|
|
543
|
+
variants: {
|
|
544
|
+
size: {
|
|
545
|
+
sm: "text-xs",
|
|
546
|
+
md: "text-sm",
|
|
547
|
+
lg: "text-base"
|
|
548
|
+
},
|
|
549
|
+
error: {
|
|
550
|
+
true: "text-[var(--ui-error)]",
|
|
551
|
+
false: ""
|
|
552
|
+
}
|
|
553
|
+
},
|
|
554
|
+
defaultVariants: {
|
|
555
|
+
size: "md",
|
|
556
|
+
error: false
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
);
|
|
560
|
+
var Label = React15.forwardRef(
|
|
561
|
+
({ className, size, error, required, children, ...props }, ref) => {
|
|
562
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
563
|
+
"label",
|
|
564
|
+
{
|
|
565
|
+
ref,
|
|
566
|
+
className: cn(labelVariants({ size, error }), className),
|
|
567
|
+
...props,
|
|
568
|
+
children: [
|
|
569
|
+
children,
|
|
570
|
+
required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[var(--ui-error)] ml-0.5", "aria-hidden": "true", children: "*" })
|
|
571
|
+
]
|
|
572
|
+
}
|
|
573
|
+
);
|
|
574
|
+
}
|
|
575
|
+
);
|
|
576
|
+
Label.displayName = "Label";
|
|
577
|
+
var FormFieldContext = React15.createContext(null);
|
|
578
|
+
function useFormField() {
|
|
579
|
+
const context = React15.useContext(FormFieldContext);
|
|
580
|
+
return context;
|
|
581
|
+
}
|
|
582
|
+
var FormField = React15.forwardRef(
|
|
583
|
+
({ className, isRequired, isInvalid, isDisabled, children, ...props }, ref) => {
|
|
584
|
+
const generatedId = React15.useId();
|
|
585
|
+
const id = props.id || generatedId;
|
|
586
|
+
const labelId = `${id}-label`;
|
|
587
|
+
const descriptionId = `${id}-description`;
|
|
588
|
+
const errorId = `${id}-error`;
|
|
589
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
590
|
+
FormFieldContext.Provider,
|
|
591
|
+
{
|
|
592
|
+
value: {
|
|
593
|
+
id,
|
|
594
|
+
labelId,
|
|
595
|
+
descriptionId,
|
|
596
|
+
errorId,
|
|
597
|
+
isRequired,
|
|
598
|
+
isInvalid,
|
|
599
|
+
isDisabled
|
|
600
|
+
},
|
|
601
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("space-y-1.5 w-full", className), ...props, children })
|
|
602
|
+
}
|
|
603
|
+
);
|
|
604
|
+
}
|
|
605
|
+
);
|
|
606
|
+
FormField.displayName = "FormField";
|
|
607
|
+
var FormLabel = React15.forwardRef(
|
|
608
|
+
({ className, required, children, ...props }, ref) => {
|
|
609
|
+
const context = useFormField();
|
|
610
|
+
const isRequired = required ?? context?.isRequired;
|
|
611
|
+
const isError = context?.isInvalid;
|
|
612
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
613
|
+
Label,
|
|
614
|
+
{
|
|
615
|
+
ref,
|
|
616
|
+
id: context?.labelId,
|
|
617
|
+
htmlFor: context?.id,
|
|
618
|
+
required: isRequired,
|
|
619
|
+
error: isError,
|
|
620
|
+
className,
|
|
621
|
+
...props,
|
|
622
|
+
children
|
|
623
|
+
}
|
|
624
|
+
);
|
|
625
|
+
}
|
|
626
|
+
);
|
|
627
|
+
FormLabel.displayName = "FormLabel";
|
|
628
|
+
var FormHelperText = React15.forwardRef(
|
|
629
|
+
({ className, children, ...props }, ref) => {
|
|
630
|
+
const context = useFormField();
|
|
631
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
632
|
+
"p",
|
|
633
|
+
{
|
|
634
|
+
ref,
|
|
635
|
+
id: context?.descriptionId,
|
|
636
|
+
className: cn("text-xs text-[var(--ui-text-muted)]", className),
|
|
637
|
+
...props,
|
|
638
|
+
children
|
|
639
|
+
}
|
|
640
|
+
);
|
|
641
|
+
}
|
|
642
|
+
);
|
|
643
|
+
FormHelperText.displayName = "FormHelperText";
|
|
644
|
+
var FormErrorMessage = React15.forwardRef(
|
|
645
|
+
({ className, children, ...props }, ref) => {
|
|
646
|
+
const context = useFormField();
|
|
647
|
+
if (!context?.isInvalid && !children) return null;
|
|
648
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
649
|
+
"p",
|
|
650
|
+
{
|
|
651
|
+
ref,
|
|
652
|
+
id: context?.errorId,
|
|
653
|
+
role: "alert",
|
|
654
|
+
className: cn("text-xs font-medium text-[var(--ui-error)]", className),
|
|
655
|
+
...props,
|
|
656
|
+
children
|
|
657
|
+
}
|
|
658
|
+
);
|
|
659
|
+
}
|
|
660
|
+
);
|
|
661
|
+
FormErrorMessage.displayName = "FormErrorMessage";
|
|
662
|
+
var CheckboxGroupContext = React15.createContext(null);
|
|
663
|
+
var useCheckboxGroup = () => React15.useContext(CheckboxGroupContext);
|
|
664
|
+
var CheckboxGroup = React15.forwardRef(
|
|
665
|
+
({
|
|
666
|
+
className,
|
|
667
|
+
orientation = "vertical",
|
|
668
|
+
children,
|
|
669
|
+
value: controlledValue,
|
|
670
|
+
defaultValue = [],
|
|
671
|
+
onChange,
|
|
672
|
+
disabled,
|
|
673
|
+
name,
|
|
674
|
+
...props
|
|
675
|
+
}, ref) => {
|
|
676
|
+
const [internalValue, setInternalValue] = React15.useState(defaultValue);
|
|
677
|
+
const isControlled = controlledValue !== void 0;
|
|
678
|
+
const value = isControlled ? controlledValue : internalValue;
|
|
679
|
+
const handleValueChange = (nextValue) => {
|
|
680
|
+
if (!isControlled) {
|
|
681
|
+
setInternalValue(nextValue);
|
|
682
|
+
}
|
|
683
|
+
onChange?.(nextValue);
|
|
684
|
+
};
|
|
685
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
686
|
+
CheckboxGroupContext.Provider,
|
|
687
|
+
{
|
|
688
|
+
value: {
|
|
689
|
+
value,
|
|
690
|
+
onChange: handleValueChange,
|
|
691
|
+
disabled,
|
|
692
|
+
name
|
|
693
|
+
},
|
|
694
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
695
|
+
"div",
|
|
696
|
+
{
|
|
697
|
+
ref,
|
|
698
|
+
role: "group",
|
|
699
|
+
className: cn(
|
|
700
|
+
"flex gap-2",
|
|
701
|
+
orientation === "vertical" ? "flex-col" : "flex-row flex-wrap items-center",
|
|
702
|
+
className
|
|
703
|
+
),
|
|
704
|
+
...props,
|
|
705
|
+
children
|
|
706
|
+
}
|
|
707
|
+
)
|
|
708
|
+
}
|
|
709
|
+
);
|
|
710
|
+
}
|
|
711
|
+
);
|
|
712
|
+
CheckboxGroup.displayName = "CheckboxGroup";
|
|
713
|
+
var checkboxVariants = classVarianceAuthority.cva(
|
|
714
|
+
"peer shrink-0 rounded-[var(--ui-radius-sm)] border border-[var(--ui-border-default)] bg-[var(--ui-bg-surface)] transition-all flex items-center justify-center text-[var(--ui-primary-fg)] peer-focus-visible:ring-2 peer-focus-visible:ring-[var(--ui-primary)] peer-focus-visible:ring-offset-2",
|
|
715
|
+
{
|
|
716
|
+
variants: {
|
|
717
|
+
size: {
|
|
718
|
+
sm: "w-4 h-4 text-xs",
|
|
719
|
+
md: "w-5 h-5 text-sm",
|
|
720
|
+
lg: "w-6 h-6 text-base"
|
|
721
|
+
}
|
|
722
|
+
},
|
|
723
|
+
defaultVariants: {
|
|
724
|
+
size: "md"
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
);
|
|
728
|
+
var Checkbox = React15.forwardRef(
|
|
729
|
+
({
|
|
730
|
+
className,
|
|
731
|
+
size,
|
|
732
|
+
indeterminate = false,
|
|
733
|
+
label,
|
|
734
|
+
checked,
|
|
735
|
+
defaultChecked = false,
|
|
736
|
+
disabled,
|
|
737
|
+
id,
|
|
738
|
+
name,
|
|
739
|
+
value: propValue,
|
|
740
|
+
onChange,
|
|
741
|
+
onCheckedChange,
|
|
742
|
+
...props
|
|
743
|
+
}, ref) => {
|
|
744
|
+
const formField = useFormField();
|
|
745
|
+
const group = useCheckboxGroup();
|
|
746
|
+
const isGroupMember = group !== null && propValue !== void 0;
|
|
747
|
+
const isDisabled = disabled ?? group?.disabled ?? formField?.isDisabled ?? false;
|
|
748
|
+
const checkboxId = id || formField?.id;
|
|
749
|
+
const checkboxName = name || group?.name;
|
|
750
|
+
const isControlled = checked !== void 0;
|
|
751
|
+
const [internalChecked, setInternalChecked] = React15.useState(defaultChecked);
|
|
752
|
+
const isChecked = isGroupMember ? group.value.includes(String(propValue)) : isControlled ? Boolean(checked) : internalChecked;
|
|
753
|
+
const innerRef = React15.useRef(null);
|
|
754
|
+
React15.useImperativeHandle(ref, () => innerRef.current);
|
|
755
|
+
React15.useEffect(() => {
|
|
756
|
+
if (innerRef.current) {
|
|
757
|
+
innerRef.current.indeterminate = Boolean(indeterminate);
|
|
758
|
+
}
|
|
759
|
+
}, [indeterminate]);
|
|
760
|
+
const handleChange = (e) => {
|
|
761
|
+
if (isDisabled) return;
|
|
762
|
+
const newChecked = e.target.checked;
|
|
763
|
+
if (!isControlled && !isGroupMember) {
|
|
764
|
+
setInternalChecked(newChecked);
|
|
765
|
+
}
|
|
766
|
+
if (isGroupMember && group) {
|
|
767
|
+
const val = String(propValue);
|
|
768
|
+
const next = newChecked ? [...group.value, val] : group.value.filter((v) => v !== val);
|
|
769
|
+
group.onChange(next);
|
|
770
|
+
}
|
|
771
|
+
onChange?.(e);
|
|
772
|
+
onCheckedChange?.(newChecked);
|
|
773
|
+
};
|
|
774
|
+
const isVisualActive = isChecked || indeterminate;
|
|
775
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
776
|
+
"label",
|
|
777
|
+
{
|
|
778
|
+
className: cn(
|
|
779
|
+
"inline-flex items-center gap-2 select-none cursor-pointer group",
|
|
780
|
+
isDisabled && "cursor-not-allowed opacity-50"
|
|
781
|
+
),
|
|
782
|
+
children: [
|
|
783
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex items-center justify-center", children: [
|
|
784
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
785
|
+
"input",
|
|
786
|
+
{
|
|
787
|
+
ref: innerRef,
|
|
788
|
+
type: "checkbox",
|
|
789
|
+
id: checkboxId,
|
|
790
|
+
name: checkboxName,
|
|
791
|
+
value: propValue,
|
|
792
|
+
disabled: isDisabled,
|
|
793
|
+
checked: isChecked,
|
|
794
|
+
onChange: handleChange,
|
|
795
|
+
"aria-checked": indeterminate ? "mixed" : isChecked,
|
|
796
|
+
className: "sr-only peer",
|
|
797
|
+
...props
|
|
798
|
+
}
|
|
799
|
+
),
|
|
800
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
801
|
+
"div",
|
|
802
|
+
{
|
|
803
|
+
className: cn(
|
|
804
|
+
checkboxVariants({ size }),
|
|
805
|
+
isVisualActive ? "bg-[var(--ui-primary)] border-[var(--ui-primary)] text-white" : "hover:border-[var(--ui-border-strong)]",
|
|
806
|
+
className
|
|
807
|
+
),
|
|
808
|
+
children: indeterminate ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Minus, { className: "w-3.5 h-3.5 stroke-[3]" }) : isChecked && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "w-3.5 h-3.5 stroke-[3]" })
|
|
809
|
+
}
|
|
810
|
+
)
|
|
811
|
+
] }),
|
|
812
|
+
label && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium text-[var(--ui-text-primary)]", children: label })
|
|
813
|
+
]
|
|
814
|
+
}
|
|
815
|
+
);
|
|
816
|
+
}
|
|
817
|
+
);
|
|
818
|
+
Checkbox.displayName = "Checkbox";
|
|
540
819
|
function DataTablePro({
|
|
541
820
|
data,
|
|
542
821
|
columns,
|
|
@@ -544,79 +823,183 @@ function DataTablePro({
|
|
|
544
823
|
searchable = true,
|
|
545
824
|
searchPlaceholder = "Search all records...",
|
|
546
825
|
selectable = true,
|
|
826
|
+
selectedKeys: controlledSelectedKeys,
|
|
827
|
+
defaultSelectedKeys = [],
|
|
547
828
|
onSelectionChange,
|
|
548
829
|
pageSize: initialPageSize = 10,
|
|
549
830
|
pageSizeOptions = [5, 10, 25, 50],
|
|
550
831
|
title,
|
|
551
832
|
description,
|
|
552
833
|
actions,
|
|
553
|
-
className
|
|
834
|
+
className,
|
|
835
|
+
loading = false,
|
|
836
|
+
// Multi-column sorting
|
|
837
|
+
multiSort = true,
|
|
838
|
+
sorting: controlledSorting,
|
|
839
|
+
defaultSorting = [],
|
|
840
|
+
onSortingChange,
|
|
841
|
+
// Server-side / manual mode props
|
|
842
|
+
manualPagination = false,
|
|
843
|
+
manualSorting = false,
|
|
844
|
+
manualFiltering = false,
|
|
845
|
+
pageIndex: controlledPageIndex,
|
|
846
|
+
pageCount: controlledPageCount,
|
|
847
|
+
totalCount: controlledTotalCount,
|
|
848
|
+
onPaginationChange,
|
|
849
|
+
searchQuery: controlledSearchQuery,
|
|
850
|
+
onSearchChange,
|
|
851
|
+
onSelectAllDataset,
|
|
852
|
+
emptyText = "No matching records found."
|
|
554
853
|
}) {
|
|
555
|
-
const [
|
|
556
|
-
const
|
|
557
|
-
const [
|
|
558
|
-
const [
|
|
559
|
-
const [
|
|
560
|
-
const
|
|
561
|
-
const
|
|
562
|
-
|
|
854
|
+
const [internalSearch, setInternalSearch] = React15.useState("");
|
|
855
|
+
const search = controlledSearchQuery !== void 0 ? controlledSearchQuery : internalSearch;
|
|
856
|
+
const [internalSorting, setInternalSorting] = React15.useState(defaultSorting);
|
|
857
|
+
const currentSorting = controlledSorting !== void 0 ? controlledSorting ?? [] : internalSorting;
|
|
858
|
+
const [internalCurrentPage, setInternalCurrentPage] = React15.useState(1);
|
|
859
|
+
const currentPage = controlledPageIndex !== void 0 ? controlledPageIndex : internalCurrentPage;
|
|
860
|
+
const [internalPageSize, setInternalPageSize] = React15.useState(initialPageSize);
|
|
861
|
+
const pageSize = internalPageSize;
|
|
862
|
+
const [internalSelectedKeys, setInternalSelectedKeys] = React15.useState(defaultSelectedKeys);
|
|
863
|
+
const isSelectedControlled = controlledSelectedKeys !== void 0;
|
|
864
|
+
const selectedKeys = isSelectedControlled ? controlledSelectedKeys : internalSelectedKeys;
|
|
865
|
+
const handleSelectionUpdate = (nextKeys) => {
|
|
866
|
+
if (!isSelectedControlled) {
|
|
867
|
+
setInternalSelectedKeys(nextKeys);
|
|
868
|
+
}
|
|
869
|
+
onSelectionChange?.(nextKeys);
|
|
870
|
+
};
|
|
871
|
+
const filteredData = React15.useMemo(() => {
|
|
872
|
+
if (manualFiltering || !search.trim()) return data;
|
|
563
873
|
const q = search.toLowerCase();
|
|
564
874
|
return data.filter((row) => {
|
|
565
|
-
return
|
|
875
|
+
return columns.some((col) => {
|
|
876
|
+
const val = col.accessor ? col.accessor(row) : row[col.key];
|
|
566
877
|
if (val === null || val === void 0) return false;
|
|
567
878
|
return String(val).toLowerCase().includes(q);
|
|
568
879
|
});
|
|
569
880
|
});
|
|
570
|
-
}, [data, search]);
|
|
571
|
-
const sortedData =
|
|
572
|
-
if (
|
|
573
|
-
const col = columns.find((c) => c.key === sortKey);
|
|
881
|
+
}, [data, search, columns, manualFiltering]);
|
|
882
|
+
const sortedData = React15.useMemo(() => {
|
|
883
|
+
if (manualSorting || currentSorting.length === 0) return filteredData;
|
|
574
884
|
return [...filteredData].sort((a, b) => {
|
|
575
|
-
const
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
885
|
+
for (const { key, direction } of currentSorting) {
|
|
886
|
+
const col = columns.find((c) => c.key === key);
|
|
887
|
+
let comp = 0;
|
|
888
|
+
if (col?.sortComparator) {
|
|
889
|
+
comp = col.sortComparator(a, b);
|
|
890
|
+
} else {
|
|
891
|
+
const valA = col?.accessor ? col.accessor(a) : a[key];
|
|
892
|
+
const valB = col?.accessor ? col.accessor(b) : b[key];
|
|
893
|
+
if (valA === valB) continue;
|
|
894
|
+
if (valA === null || valA === void 0) return 1;
|
|
895
|
+
if (valB === null || valB === void 0) return -1;
|
|
896
|
+
comp = valA < valB ? -1 : 1;
|
|
897
|
+
}
|
|
898
|
+
if (comp !== 0) {
|
|
899
|
+
return direction === "asc" ? comp : -comp;
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
return 0;
|
|
582
903
|
});
|
|
583
|
-
}, [filteredData,
|
|
584
|
-
const
|
|
585
|
-
const
|
|
904
|
+
}, [filteredData, currentSorting, columns, manualSorting]);
|
|
905
|
+
const totalItems = controlledTotalCount !== void 0 ? controlledTotalCount : sortedData.length;
|
|
906
|
+
const totalPages = controlledPageCount !== void 0 ? Math.max(1, controlledPageCount) : Math.max(1, Math.ceil(totalItems / pageSize));
|
|
907
|
+
React15.useEffect(() => {
|
|
908
|
+
if (!manualPagination && currentPage > totalPages && totalPages > 0) {
|
|
909
|
+
setInternalCurrentPage(totalPages);
|
|
910
|
+
onPaginationChange?.(totalPages, pageSize);
|
|
911
|
+
}
|
|
912
|
+
}, [totalPages, currentPage, manualPagination, pageSize, onPaginationChange]);
|
|
913
|
+
const paginatedData = React15.useMemo(() => {
|
|
914
|
+
if (manualPagination) return data;
|
|
586
915
|
const start = (currentPage - 1) * pageSize;
|
|
587
916
|
return sortedData.slice(start, start + pageSize);
|
|
588
|
-
}, [sortedData, currentPage, pageSize]);
|
|
589
|
-
const handleSort = (key) => {
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
917
|
+
}, [data, sortedData, currentPage, pageSize, manualPagination]);
|
|
918
|
+
const handleSort = (key, e) => {
|
|
919
|
+
const isShift = e?.shiftKey || false;
|
|
920
|
+
let nextSorting = [...currentSorting];
|
|
921
|
+
const existingIdx = nextSorting.findIndex((s) => s.key === key);
|
|
922
|
+
if (isShift && multiSort) {
|
|
923
|
+
if (existingIdx >= 0) {
|
|
924
|
+
if (nextSorting[existingIdx].direction === "asc") {
|
|
925
|
+
nextSorting[existingIdx] = { key, direction: "desc" };
|
|
926
|
+
} else {
|
|
927
|
+
nextSorting.splice(existingIdx, 1);
|
|
928
|
+
}
|
|
593
929
|
} else {
|
|
594
|
-
|
|
595
|
-
setSortDirection("asc");
|
|
930
|
+
nextSorting.push({ key, direction: "asc" });
|
|
596
931
|
}
|
|
597
932
|
} else {
|
|
598
|
-
|
|
599
|
-
|
|
933
|
+
if (existingIdx >= 0 && nextSorting.length === 1) {
|
|
934
|
+
if (nextSorting[0].direction === "asc") {
|
|
935
|
+
nextSorting = [{ key, direction: "desc" }];
|
|
936
|
+
} else {
|
|
937
|
+
nextSorting = [];
|
|
938
|
+
}
|
|
939
|
+
} else {
|
|
940
|
+
nextSorting = [{ key, direction: "asc" }];
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
if (controlledSorting === void 0) {
|
|
944
|
+
setInternalSorting(nextSorting);
|
|
600
945
|
}
|
|
946
|
+
onSortingChange?.(nextSorting);
|
|
601
947
|
};
|
|
602
|
-
const
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
948
|
+
const handlePageChange = (newPage) => {
|
|
949
|
+
const clamped = Math.max(1, Math.min(totalPages, newPage));
|
|
950
|
+
if (controlledPageIndex === void 0) {
|
|
951
|
+
setInternalCurrentPage(clamped);
|
|
952
|
+
}
|
|
953
|
+
onPaginationChange?.(clamped, pageSize);
|
|
954
|
+
};
|
|
955
|
+
const handlePageSizeChange = (newSize) => {
|
|
956
|
+
setInternalPageSize(newSize);
|
|
957
|
+
if (controlledPageIndex === void 0) {
|
|
958
|
+
setInternalCurrentPage(1);
|
|
959
|
+
}
|
|
960
|
+
onPaginationChange?.(1, newSize);
|
|
961
|
+
};
|
|
962
|
+
const handleSearchChange = (query) => {
|
|
963
|
+
if (controlledSearchQuery === void 0) {
|
|
964
|
+
setInternalSearch(query);
|
|
965
|
+
if (controlledPageIndex === void 0) {
|
|
966
|
+
setInternalCurrentPage(1);
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
onSearchChange?.(query);
|
|
970
|
+
};
|
|
971
|
+
const currentPageKeys = React15.useMemo(() => paginatedData.map(keyExtractor), [paginatedData, keyExtractor]);
|
|
972
|
+
const isAllCurrentPageSelected = currentPageKeys.length > 0 && currentPageKeys.every((k) => selectedKeys.includes(k));
|
|
973
|
+
const isSomeCurrentPageSelected = currentPageKeys.some((k) => selectedKeys.includes(k)) && !isAllCurrentPageSelected;
|
|
974
|
+
const toggleSelectAllCurrentPage = () => {
|
|
975
|
+
if (isAllCurrentPageSelected) {
|
|
976
|
+
const next = selectedKeys.filter((k) => !currentPageKeys.includes(k));
|
|
977
|
+
handleSelectionUpdate(next);
|
|
606
978
|
} else {
|
|
607
|
-
const
|
|
608
|
-
|
|
609
|
-
onSelectionChange?.(allKeys);
|
|
979
|
+
const combined = Array.from(/* @__PURE__ */ new Set([...selectedKeys, ...currentPageKeys]));
|
|
980
|
+
handleSelectionUpdate(combined);
|
|
610
981
|
}
|
|
611
982
|
};
|
|
612
983
|
const toggleSelectRow = (key) => {
|
|
613
984
|
const next = selectedKeys.includes(key) ? selectedKeys.filter((k) => k !== key) : [...selectedKeys, key];
|
|
614
|
-
|
|
615
|
-
|
|
985
|
+
handleSelectionUpdate(next);
|
|
986
|
+
};
|
|
987
|
+
const canSelectAllDataset = !manualPagination || typeof onSelectAllDataset === "function";
|
|
988
|
+
const selectAllDataset = () => {
|
|
989
|
+
if (manualPagination) {
|
|
990
|
+
onSelectAllDataset?.();
|
|
991
|
+
return;
|
|
992
|
+
}
|
|
993
|
+
const allKeys = sortedData.map(keyExtractor);
|
|
994
|
+
handleSelectionUpdate(allKeys);
|
|
995
|
+
};
|
|
996
|
+
const clearSelection = () => {
|
|
997
|
+
handleSelectionUpdate([]);
|
|
616
998
|
};
|
|
617
999
|
const exportCSV = () => {
|
|
1000
|
+
const exportRows = manualPagination ? data : sortedData;
|
|
618
1001
|
const headers = columns.map((c) => typeof c.header === "string" ? c.header : c.key);
|
|
619
|
-
const rows =
|
|
1002
|
+
const rows = exportRows.map(
|
|
620
1003
|
(row) => columns.map((c) => {
|
|
621
1004
|
const val = c.accessor ? c.accessor(row) : row[c.key];
|
|
622
1005
|
return `"${String(val ?? "").replace(/"/g, '""')}"`;
|
|
@@ -631,7 +1014,6 @@ function DataTablePro({
|
|
|
631
1014
|
link.click();
|
|
632
1015
|
document.body.removeChild(link);
|
|
633
1016
|
};
|
|
634
|
-
const isAllSelected = paginatedData.length > 0 && selectedKeys.length === paginatedData.length;
|
|
635
1017
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("w-full space-y-4", className), children: [
|
|
636
1018
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-center justify-between gap-4", children: [
|
|
637
1019
|
(title || description) && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
@@ -647,10 +1029,7 @@ function DataTablePro({
|
|
|
647
1029
|
type: "text",
|
|
648
1030
|
placeholder: searchPlaceholder,
|
|
649
1031
|
value: search,
|
|
650
|
-
onChange: (e) =>
|
|
651
|
-
setSearch(e.target.value);
|
|
652
|
-
setCurrentPage(1);
|
|
653
|
-
},
|
|
1032
|
+
onChange: (e) => handleSearchChange(e.target.value),
|
|
654
1033
|
className: "w-full h-8 pl-8 pr-3 text-xs rounded-xl bg-[var(--ui-bg-surface)] border border-[var(--ui-border-default)] hover:border-[var(--ui-border-strong)] focus:outline-none focus:ring-2 focus:ring-[var(--ui-primary)]/40 text-[var(--ui-text-primary)] placeholder:text-[var(--ui-text-muted)] transition-all shadow-inner"
|
|
655
1034
|
}
|
|
656
1035
|
)
|
|
@@ -659,83 +1038,110 @@ function DataTablePro({
|
|
|
659
1038
|
actions
|
|
660
1039
|
] })
|
|
661
1040
|
] }),
|
|
662
|
-
selectedKeys.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-4 py-2 rounded-xl bg-[var(--ui-primary)]/15 border border-[var(--ui-primary)]/30 flex items-center justify-between animate-in fade-in duration-200", children: [
|
|
663
|
-
/* @__PURE__ */ jsxRuntime.
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
1041
|
+
selectedKeys.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-4 py-2 rounded-xl bg-[var(--ui-primary)]/15 border border-[var(--ui-primary)]/30 flex flex-wrap items-center justify-between gap-2 animate-in fade-in duration-200", children: [
|
|
1042
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-xs font-semibold text-[var(--ui-primary)]", children: [
|
|
1043
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
1044
|
+
"Selected ",
|
|
1045
|
+
selectedKeys.length,
|
|
1046
|
+
" records"
|
|
1047
|
+
] }),
|
|
1048
|
+
canSelectAllDataset && selectedKeys.length < totalItems && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1049
|
+
"button",
|
|
1050
|
+
{
|
|
1051
|
+
type: "button",
|
|
1052
|
+
onClick: selectAllDataset,
|
|
1053
|
+
className: "underline hover:text-[var(--ui-primary)]/80 cursor-pointer font-bold ml-1",
|
|
1054
|
+
children: [
|
|
1055
|
+
"Select all ",
|
|
1056
|
+
totalItems,
|
|
1057
|
+
" records"
|
|
1058
|
+
]
|
|
1059
|
+
}
|
|
1060
|
+
)
|
|
1061
|
+
] }),
|
|
670
1062
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
671
1063
|
Button,
|
|
672
1064
|
{
|
|
673
1065
|
size: "xs",
|
|
674
1066
|
variant: "ghost",
|
|
675
1067
|
className: "text-xs text-rose-500 hover:text-rose-600 hover:bg-rose-500/10",
|
|
676
|
-
onClick:
|
|
677
|
-
setSelectedKeys([]);
|
|
678
|
-
onSelectionChange?.([]);
|
|
679
|
-
},
|
|
1068
|
+
onClick: clearSelection,
|
|
680
1069
|
children: "Clear Selection"
|
|
681
1070
|
}
|
|
682
1071
|
)
|
|
683
1072
|
] }),
|
|
684
|
-
/* @__PURE__ */ jsxRuntime.
|
|
685
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
686
|
-
|
|
687
|
-
|
|
1073
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative w-full overflow-x-auto rounded-2xl border border-[var(--ui-border-default)] bg-[var(--ui-bg-surface)] shadow-sm", children: [
|
|
1074
|
+
loading && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 z-20 bg-[var(--ui-bg-surface)]/60 backdrop-blur-xs flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "w-6 h-6 animate-spin text-[var(--ui-primary)]" }) }),
|
|
1075
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Table, { children: [
|
|
1076
|
+
/* @__PURE__ */ jsxRuntime.jsx(TableHeader, { children: /* @__PURE__ */ jsxRuntime.jsxs(TableRow, { children: [
|
|
1077
|
+
selectable && /* @__PURE__ */ jsxRuntime.jsx(TableHead, { className: "w-10 px-4", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1078
|
+
Checkbox,
|
|
1079
|
+
{
|
|
1080
|
+
checked: isAllCurrentPageSelected,
|
|
1081
|
+
indeterminate: isSomeCurrentPageSelected,
|
|
1082
|
+
onCheckedChange: toggleSelectAllCurrentPage,
|
|
1083
|
+
"aria-label": "Select all on page"
|
|
1084
|
+
}
|
|
1085
|
+
) }),
|
|
1086
|
+
columns.map((col) => {
|
|
1087
|
+
const sortIndex = currentSorting.findIndex((s) => s.key === col.key);
|
|
1088
|
+
const sortRule = sortIndex >= 0 ? currentSorting[sortIndex] : null;
|
|
1089
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1090
|
+
TableHead,
|
|
1091
|
+
{
|
|
1092
|
+
style: { width: col.width },
|
|
1093
|
+
onClick: (e) => col.sortable !== false && handleSort(col.key, e),
|
|
1094
|
+
className: cn(
|
|
1095
|
+
col.sortable !== false && "cursor-pointer select-none hover:text-[var(--ui-text-primary)] transition-colors"
|
|
1096
|
+
),
|
|
1097
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
1098
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: col.header }),
|
|
1099
|
+
col.sortable !== false && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-0.5 text-[var(--ui-text-muted)]", children: [
|
|
1100
|
+
sortRule ? sortRule.direction === "asc" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronUp, { className: "w-3.5 h-3.5 text-[var(--ui-primary)] font-bold" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "w-3.5 h-3.5 text-[var(--ui-primary)] font-bold" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronsUpDown, { className: "w-3 h-3 opacity-40" }),
|
|
1101
|
+
currentSorting.length > 1 && sortIndex >= 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-mono font-bold text-[var(--ui-primary)]", children: sortIndex + 1 })
|
|
1102
|
+
] })
|
|
1103
|
+
] })
|
|
1104
|
+
},
|
|
1105
|
+
col.key
|
|
1106
|
+
);
|
|
1107
|
+
})
|
|
1108
|
+
] }) }),
|
|
1109
|
+
/* @__PURE__ */ jsxRuntime.jsx(TableBody, { children: paginatedData.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(TableRow, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1110
|
+
TableCell,
|
|
688
1111
|
{
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
className: "rounded border-[var(--ui-border-default)] text-[var(--ui-primary)] focus:ring-[var(--ui-primary)] cursor-pointer"
|
|
1112
|
+
colSpan: columns.length + (selectable ? 1 : 0),
|
|
1113
|
+
className: "h-32 text-center text-xs text-[var(--ui-text-muted)]",
|
|
1114
|
+
children: emptyText
|
|
693
1115
|
}
|
|
694
|
-
) }),
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
type: "checkbox",
|
|
724
|
-
checked: isSelected,
|
|
725
|
-
onChange: () => toggleSelectRow(key),
|
|
726
|
-
className: "rounded border-[var(--ui-border-default)] text-[var(--ui-primary)] focus:ring-[var(--ui-primary)] cursor-pointer"
|
|
727
|
-
}
|
|
728
|
-
) }),
|
|
729
|
-
columns.map((col) => {
|
|
730
|
-
const cellContent = col.render ? col.render(row, rowIdx) : col.accessor ? col.accessor(row) : row[col.key];
|
|
731
|
-
return /* @__PURE__ */ jsxRuntime.jsx(TableCell, { children: cellContent }, col.key);
|
|
732
|
-
})
|
|
733
|
-
]
|
|
734
|
-
},
|
|
735
|
-
key
|
|
736
|
-
);
|
|
737
|
-
}) })
|
|
738
|
-
] }) }),
|
|
1116
|
+
) }) : paginatedData.map((row, rowIdx) => {
|
|
1117
|
+
const key = keyExtractor(row);
|
|
1118
|
+
const isSelected = selectedKeys.includes(key);
|
|
1119
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1120
|
+
TableRow,
|
|
1121
|
+
{
|
|
1122
|
+
"data-state": isSelected ? "selected" : void 0,
|
|
1123
|
+
className: cn(isSelected && "bg-[var(--ui-primary)]/10"),
|
|
1124
|
+
children: [
|
|
1125
|
+
selectable && /* @__PURE__ */ jsxRuntime.jsx(TableCell, { className: "w-10 px-4", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1126
|
+
Checkbox,
|
|
1127
|
+
{
|
|
1128
|
+
checked: isSelected,
|
|
1129
|
+
onCheckedChange: () => toggleSelectRow(key),
|
|
1130
|
+
"aria-label": `Select row ${key}`
|
|
1131
|
+
}
|
|
1132
|
+
) }),
|
|
1133
|
+
columns.map((col) => {
|
|
1134
|
+
const val = col.accessor ? col.accessor(row) : row[col.key];
|
|
1135
|
+
const cellContent = col.render ? col.render(row, rowIdx, val) : val;
|
|
1136
|
+
return /* @__PURE__ */ jsxRuntime.jsx(TableCell, { children: cellContent }, col.key);
|
|
1137
|
+
})
|
|
1138
|
+
]
|
|
1139
|
+
},
|
|
1140
|
+
key
|
|
1141
|
+
);
|
|
1142
|
+
}) })
|
|
1143
|
+
] })
|
|
1144
|
+
] }),
|
|
739
1145
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-center justify-between gap-3 px-1 text-xs text-[var(--ui-text-muted)] font-mono", children: [
|
|
740
1146
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
741
1147
|
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Rows per page:" }),
|
|
@@ -743,21 +1149,18 @@ function DataTablePro({
|
|
|
743
1149
|
"select",
|
|
744
1150
|
{
|
|
745
1151
|
value: pageSize,
|
|
746
|
-
onChange: (e) =>
|
|
747
|
-
setPageSize(Number(e.target.value));
|
|
748
|
-
setCurrentPage(1);
|
|
749
|
-
},
|
|
1152
|
+
onChange: (e) => handlePageSizeChange(Number(e.target.value)),
|
|
750
1153
|
className: "px-2 py-1 rounded-lg bg-[var(--ui-bg-surface)] border border-[var(--ui-border-default)] text-[var(--ui-text-primary)] font-mono text-xs focus:outline-none",
|
|
751
1154
|
children: pageSizeOptions.map((opt) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: opt, children: opt }, opt))
|
|
752
1155
|
}
|
|
753
1156
|
),
|
|
754
1157
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[var(--ui-text-muted)]", children: [
|
|
755
1158
|
"Showing ",
|
|
756
|
-
Math.min((currentPage - 1) * pageSize + 1,
|
|
1159
|
+
totalItems === 0 ? 0 : Math.min((currentPage - 1) * pageSize + 1, totalItems),
|
|
757
1160
|
"\u2013",
|
|
758
|
-
Math.min(currentPage * pageSize,
|
|
1161
|
+
Math.min(currentPage * pageSize, totalItems),
|
|
759
1162
|
" of ",
|
|
760
|
-
|
|
1163
|
+
totalItems
|
|
761
1164
|
] })
|
|
762
1165
|
] }),
|
|
763
1166
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
@@ -766,8 +1169,9 @@ function DataTablePro({
|
|
|
766
1169
|
{
|
|
767
1170
|
size: "xs",
|
|
768
1171
|
variant: "outline",
|
|
769
|
-
disabled: currentPage
|
|
770
|
-
onClick: () =>
|
|
1172
|
+
disabled: currentPage <= 1 || loading,
|
|
1173
|
+
onClick: () => handlePageChange(currentPage - 1),
|
|
1174
|
+
"aria-label": "Previous page",
|
|
771
1175
|
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeft, { className: "w-3.5 h-3.5" })
|
|
772
1176
|
}
|
|
773
1177
|
),
|
|
@@ -781,8 +1185,9 @@ function DataTablePro({
|
|
|
781
1185
|
{
|
|
782
1186
|
size: "xs",
|
|
783
1187
|
variant: "outline",
|
|
784
|
-
disabled: currentPage
|
|
785
|
-
onClick: () =>
|
|
1188
|
+
disabled: currentPage >= totalPages || loading,
|
|
1189
|
+
onClick: () => handlePageChange(currentPage + 1),
|
|
1190
|
+
"aria-label": "Next page",
|
|
786
1191
|
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "w-3.5 h-3.5" })
|
|
787
1192
|
}
|
|
788
1193
|
)
|
|
@@ -790,106 +1195,224 @@ function DataTablePro({
|
|
|
790
1195
|
] })
|
|
791
1196
|
] });
|
|
792
1197
|
}
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
return
|
|
814
|
-
}
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
1198
|
+
var TreeView = React15.forwardRef(
|
|
1199
|
+
({
|
|
1200
|
+
data,
|
|
1201
|
+
selectedId,
|
|
1202
|
+
defaultExpandedIds,
|
|
1203
|
+
onSelect,
|
|
1204
|
+
onExpandedChange,
|
|
1205
|
+
className,
|
|
1206
|
+
"aria-label": ariaLabel = "Tree View"
|
|
1207
|
+
}, ref) => {
|
|
1208
|
+
const initialExpanded = React15.useMemo(() => {
|
|
1209
|
+
if (defaultExpandedIds) return new Set(defaultExpandedIds);
|
|
1210
|
+
const set = /* @__PURE__ */ new Set();
|
|
1211
|
+
const collect = (items) => {
|
|
1212
|
+
for (const it of items) {
|
|
1213
|
+
if (it.defaultExpanded) set.add(it.id);
|
|
1214
|
+
if (it.children) collect(it.children);
|
|
1215
|
+
}
|
|
1216
|
+
};
|
|
1217
|
+
collect(data);
|
|
1218
|
+
return set;
|
|
1219
|
+
}, [data, defaultExpandedIds]);
|
|
1220
|
+
const [expandedSet, setExpandedSet] = React15.useState(initialExpanded);
|
|
1221
|
+
const [focusedId, setFocusedId] = React15.useState(null);
|
|
1222
|
+
const itemRefs = React15.useRef(/* @__PURE__ */ new Map());
|
|
1223
|
+
const focusNode = (id) => {
|
|
1224
|
+
setFocusedId(id);
|
|
1225
|
+
const el = itemRefs.current.get(id);
|
|
1226
|
+
if (el) {
|
|
1227
|
+
el.focus();
|
|
1228
|
+
}
|
|
1229
|
+
};
|
|
1230
|
+
const toggleExpand = (id) => {
|
|
1231
|
+
setExpandedSet((prev) => {
|
|
1232
|
+
const next = new Set(prev);
|
|
1233
|
+
if (next.has(id)) next.delete(id);
|
|
1234
|
+
else next.add(id);
|
|
1235
|
+
onExpandedChange?.(Array.from(next));
|
|
1236
|
+
return next;
|
|
1237
|
+
});
|
|
1238
|
+
};
|
|
1239
|
+
const expandNode = (id) => {
|
|
1240
|
+
if (!expandedSet.has(id)) {
|
|
1241
|
+
setExpandedSet((prev) => {
|
|
1242
|
+
const next = new Set(prev).add(id);
|
|
1243
|
+
onExpandedChange?.(Array.from(next));
|
|
1244
|
+
return next;
|
|
1245
|
+
});
|
|
1246
|
+
}
|
|
1247
|
+
};
|
|
1248
|
+
const collapseNode = (id) => {
|
|
1249
|
+
if (expandedSet.has(id)) {
|
|
1250
|
+
setExpandedSet((prev) => {
|
|
1251
|
+
const next = new Set(prev);
|
|
1252
|
+
next.delete(id);
|
|
1253
|
+
onExpandedChange?.(Array.from(next));
|
|
1254
|
+
return next;
|
|
1255
|
+
});
|
|
1256
|
+
}
|
|
1257
|
+
};
|
|
1258
|
+
const visibleList = React15.useMemo(() => {
|
|
1259
|
+
const list = [];
|
|
1260
|
+
const traverse = (items, level, parentId) => {
|
|
1261
|
+
for (const item of items) {
|
|
1262
|
+
const hasChildren = Boolean(item.children && item.children.length > 0);
|
|
1263
|
+
list.push({ item, level, parentId, hasChildren });
|
|
1264
|
+
if (hasChildren && expandedSet.has(item.id)) {
|
|
1265
|
+
traverse(item.children, level + 1, item.id);
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1268
|
+
};
|
|
1269
|
+
traverse(data, 0, null);
|
|
1270
|
+
return list;
|
|
1271
|
+
}, [data, expandedSet]);
|
|
1272
|
+
const handleKeyDown = (e) => {
|
|
1273
|
+
if (visibleList.length === 0) return;
|
|
1274
|
+
const currentIdx = focusedId ? visibleList.findIndex((f) => f.item.id === focusedId) : 0;
|
|
1275
|
+
const currentFlat = visibleList[currentIdx] || visibleList[0];
|
|
1276
|
+
if (e.key === "ArrowDown") {
|
|
1277
|
+
e.preventDefault();
|
|
1278
|
+
const nextIdx = Math.min(visibleList.length - 1, currentIdx + 1);
|
|
1279
|
+
focusNode(visibleList[nextIdx].item.id);
|
|
1280
|
+
} else if (e.key === "ArrowUp") {
|
|
1281
|
+
e.preventDefault();
|
|
1282
|
+
const prevIdx = Math.max(0, currentIdx - 1);
|
|
1283
|
+
focusNode(visibleList[prevIdx].item.id);
|
|
1284
|
+
} else if (e.key === "ArrowRight") {
|
|
1285
|
+
e.preventDefault();
|
|
1286
|
+
if (currentFlat.hasChildren) {
|
|
1287
|
+
if (!expandedSet.has(currentFlat.item.id)) {
|
|
1288
|
+
expandNode(currentFlat.item.id);
|
|
1289
|
+
} else {
|
|
1290
|
+
const nextIdx = currentIdx + 1;
|
|
1291
|
+
if (nextIdx < visibleList.length) {
|
|
1292
|
+
focusNode(visibleList[nextIdx].item.id);
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1296
|
+
} else if (e.key === "ArrowLeft") {
|
|
1297
|
+
e.preventDefault();
|
|
1298
|
+
if (currentFlat.hasChildren && expandedSet.has(currentFlat.item.id)) {
|
|
1299
|
+
collapseNode(currentFlat.item.id);
|
|
1300
|
+
} else if (currentFlat.parentId) {
|
|
1301
|
+
focusNode(currentFlat.parentId);
|
|
1302
|
+
}
|
|
1303
|
+
} else if (e.key === "Home") {
|
|
1304
|
+
e.preventDefault();
|
|
1305
|
+
focusNode(visibleList[0].item.id);
|
|
1306
|
+
} else if (e.key === "End") {
|
|
1307
|
+
e.preventDefault();
|
|
1308
|
+
focusNode(visibleList[visibleList.length - 1].item.id);
|
|
1309
|
+
} else if (e.key === "Enter" || e.key === " ") {
|
|
1310
|
+
e.preventDefault();
|
|
1311
|
+
if (currentFlat) {
|
|
1312
|
+
if (currentFlat.hasChildren) {
|
|
1313
|
+
toggleExpand(currentFlat.item.id);
|
|
1314
|
+
}
|
|
1315
|
+
onSelect?.(currentFlat.item);
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
};
|
|
1319
|
+
const getIcon = (item, hasChildren, isExpanded) => {
|
|
1320
|
+
if (item.icon) return item.icon;
|
|
1321
|
+
if (hasChildren) {
|
|
1322
|
+
return isExpanded ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FolderOpen, { className: "w-4 h-4 text-amber-500 shrink-0" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Folder, { className: "w-4 h-4 text-amber-500 shrink-0" });
|
|
1323
|
+
}
|
|
1324
|
+
if (item.label.endsWith(".tsx") || item.label.endsWith(".ts") || item.label.endsWith(".js")) {
|
|
1325
|
+
return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileCode, { className: "w-4 h-4 text-blue-500 shrink-0" });
|
|
1326
|
+
}
|
|
1327
|
+
if (item.label.endsWith(".png") || item.label.endsWith(".jpg") || item.label.endsWith(".svg")) {
|
|
1328
|
+
return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Image, { className: "w-4 h-4 text-purple-500 shrink-0" });
|
|
1329
|
+
}
|
|
1330
|
+
return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileText, { className: "w-4 h-4 text-[var(--ui-text-muted)] shrink-0" });
|
|
1331
|
+
};
|
|
1332
|
+
const renderNodes = (items, level) => {
|
|
1333
|
+
return items.map((item, index) => {
|
|
1334
|
+
const hasChildren = Boolean(item.children && item.children.length > 0);
|
|
1335
|
+
const isExpanded = expandedSet.has(item.id);
|
|
1336
|
+
const isSelected = selectedId === item.id;
|
|
1337
|
+
const isFocused = focusedId === item.id || !focusedId && level === 0 && index === 0;
|
|
1338
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "none", className: "select-none text-xs", children: [
|
|
1339
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1340
|
+
"div",
|
|
835
1341
|
{
|
|
1342
|
+
ref: (el) => {
|
|
1343
|
+
if (el) itemRefs.current.set(item.id, el);
|
|
1344
|
+
else itemRefs.current.delete(item.id);
|
|
1345
|
+
},
|
|
1346
|
+
role: "treeitem",
|
|
1347
|
+
tabIndex: isFocused ? 0 : -1,
|
|
1348
|
+
"aria-expanded": hasChildren ? isExpanded : void 0,
|
|
1349
|
+
"aria-selected": isSelected,
|
|
1350
|
+
"aria-level": level + 1,
|
|
1351
|
+
"aria-posinset": index + 1,
|
|
1352
|
+
"aria-setsize": items.length,
|
|
1353
|
+
onClick: (e) => {
|
|
1354
|
+
e.stopPropagation();
|
|
1355
|
+
focusNode(item.id);
|
|
1356
|
+
if (hasChildren) {
|
|
1357
|
+
toggleExpand(item.id);
|
|
1358
|
+
}
|
|
1359
|
+
onSelect?.(item);
|
|
1360
|
+
},
|
|
1361
|
+
style: { paddingLeft: `${level * 16 + 8}px` },
|
|
836
1362
|
className: cn(
|
|
837
|
-
"
|
|
838
|
-
isSelected ? "bg-
|
|
1363
|
+
"flex items-center justify-between py-1.5 pr-2.5 rounded-xl cursor-pointer transition-colors group outline-none focus-visible:ring-2 focus-visible:ring-[var(--ui-primary)]",
|
|
1364
|
+
isSelected ? "bg-[var(--ui-primary)] text-white font-semibold shadow-xs" : "text-[var(--ui-text-primary)] hover:bg-[var(--ui-bg-tertiary)]"
|
|
839
1365
|
),
|
|
840
|
-
children:
|
|
1366
|
+
children: [
|
|
1367
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 truncate", children: [
|
|
1368
|
+
hasChildren ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("p-0.5 rounded transition-transform duration-200", isExpanded && "rotate-90"), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: cn("w-3 h-3", isSelected ? "text-white" : "text-[var(--ui-text-muted)]") }) }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-4" }),
|
|
1369
|
+
getIcon(item, hasChildren, isExpanded),
|
|
1370
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: item.label })
|
|
1371
|
+
] }),
|
|
1372
|
+
item.badge !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1373
|
+
"span",
|
|
1374
|
+
{
|
|
1375
|
+
className: cn(
|
|
1376
|
+
"px-1.5 py-0.5 rounded-md text-[10px] font-mono",
|
|
1377
|
+
isSelected ? "bg-white/20 text-white" : "bg-[var(--ui-bg-secondary)] text-[var(--ui-text-muted)]"
|
|
1378
|
+
),
|
|
1379
|
+
children: item.badge
|
|
1380
|
+
}
|
|
1381
|
+
)
|
|
1382
|
+
]
|
|
841
1383
|
}
|
|
842
|
-
)
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
{
|
|
857
|
-
item: child,
|
|
858
|
-
level: level + 1,
|
|
859
|
-
selectedId,
|
|
860
|
-
onSelect
|
|
861
|
-
},
|
|
862
|
-
child.id
|
|
863
|
-
))
|
|
864
|
-
] })
|
|
865
|
-
] });
|
|
866
|
-
}
|
|
867
|
-
var TreeView = React11.forwardRef(
|
|
868
|
-
({ data, selectedId, onSelect, className }, ref) => {
|
|
1384
|
+
),
|
|
1385
|
+
hasChildren && isExpanded && /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "group", className: "relative space-y-0.5 animate-in fade-in duration-150", children: [
|
|
1386
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1387
|
+
"div",
|
|
1388
|
+
{
|
|
1389
|
+
className: "absolute left-[15px] top-0 bottom-0 w-[1px] bg-[var(--ui-border-subtle)]",
|
|
1390
|
+
style: { left: `${level * 16 + 15}px` }
|
|
1391
|
+
}
|
|
1392
|
+
),
|
|
1393
|
+
renderNodes(item.children, level + 1)
|
|
1394
|
+
] })
|
|
1395
|
+
] }, item.id);
|
|
1396
|
+
});
|
|
1397
|
+
};
|
|
869
1398
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
870
1399
|
"div",
|
|
871
1400
|
{
|
|
872
1401
|
ref,
|
|
1402
|
+
role: "tree",
|
|
1403
|
+
"aria-label": ariaLabel,
|
|
1404
|
+
onKeyDown: handleKeyDown,
|
|
873
1405
|
className: cn(
|
|
874
|
-
"w-full p-2 rounded-2xl bg-[var(--ui-bg-surface)] border border-[var(--ui-border-default)] space-y-0.5 shadow-sm overflow-hidden",
|
|
1406
|
+
"w-full p-2 rounded-2xl bg-[var(--ui-bg-surface)] border border-[var(--ui-border-default)] space-y-0.5 shadow-sm overflow-hidden outline-none",
|
|
875
1407
|
className
|
|
876
1408
|
),
|
|
877
|
-
children: data
|
|
878
|
-
TreeNode,
|
|
879
|
-
{
|
|
880
|
-
item,
|
|
881
|
-
level: 0,
|
|
882
|
-
selectedId,
|
|
883
|
-
onSelect
|
|
884
|
-
},
|
|
885
|
-
item.id
|
|
886
|
-
))
|
|
1409
|
+
children: renderNodes(data, 0)
|
|
887
1410
|
}
|
|
888
1411
|
);
|
|
889
1412
|
}
|
|
890
1413
|
);
|
|
891
1414
|
TreeView.displayName = "TreeView";
|
|
892
|
-
var Carousel =
|
|
1415
|
+
var Carousel = React15.forwardRef(
|
|
893
1416
|
({
|
|
894
1417
|
autoplay = false,
|
|
895
1418
|
autoplayInterval = 4e3,
|
|
@@ -900,9 +1423,9 @@ var Carousel = React11.forwardRef(
|
|
|
900
1423
|
className,
|
|
901
1424
|
...props
|
|
902
1425
|
}, ref) => {
|
|
903
|
-
const [currentIndex, setCurrentIndex] =
|
|
904
|
-
const totalSlides =
|
|
905
|
-
const timerRef =
|
|
1426
|
+
const [currentIndex, setCurrentIndex] = React15.useState(0);
|
|
1427
|
+
const totalSlides = React15__default.default.Children.count(children);
|
|
1428
|
+
const timerRef = React15.useRef(null);
|
|
906
1429
|
const nextSlide = () => {
|
|
907
1430
|
setCurrentIndex((prev) => {
|
|
908
1431
|
if (prev === totalSlides - 1) {
|
|
@@ -919,7 +1442,7 @@ var Carousel = React11.forwardRef(
|
|
|
919
1442
|
return prev - 1;
|
|
920
1443
|
});
|
|
921
1444
|
};
|
|
922
|
-
|
|
1445
|
+
React15.useEffect(() => {
|
|
923
1446
|
if (autoplay && totalSlides > 1) {
|
|
924
1447
|
timerRef.current = setInterval(nextSlide, autoplayInterval);
|
|
925
1448
|
return () => clearInterval(timerRef.current);
|
|
@@ -943,7 +1466,7 @@ var Carousel = React11.forwardRef(
|
|
|
943
1466
|
{
|
|
944
1467
|
className: "flex transition-transform duration-500 ease-out",
|
|
945
1468
|
style: { transform: `translateX(-${currentIndex * 100}%)` },
|
|
946
|
-
children:
|
|
1469
|
+
children: React15__default.default.Children.map(children, (child, idx) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full flex-shrink-0", children: child }, idx))
|
|
947
1470
|
}
|
|
948
1471
|
),
|
|
949
1472
|
showArrows && totalSlides > 1 && /* @__PURE__ */ jsxRuntime.jsx(
|