@hyddenlabs/hydn-ui 0.3.0-alpha.1 → 0.3.0-alpha.99
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/index.cjs +384 -154
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -4
- package/dist/index.d.ts +12 -4
- package/dist/index.js +309 -79
- package/dist/index.js.map +1 -1
- package/dist/style.css +2 -2
- package/package.json +11 -11
package/dist/index.cjs
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
-
var
|
|
4
|
+
var React5 = require('react');
|
|
5
5
|
var iconsReact = require('@tabler/icons-react');
|
|
6
6
|
var reactRouterDom = require('react-router-dom');
|
|
7
7
|
var reactDom = require('react-dom');
|
|
8
8
|
|
|
9
9
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
10
10
|
|
|
11
|
-
var
|
|
11
|
+
var React5__default = /*#__PURE__*/_interopDefault(React5);
|
|
12
12
|
|
|
13
13
|
// src/components/forms/button/button.tsx
|
|
14
14
|
function Button({
|
|
@@ -221,9 +221,9 @@ function Checkbox({
|
|
|
221
221
|
}
|
|
222
222
|
Checkbox.displayName = "Checkbox";
|
|
223
223
|
var checkbox_default = Checkbox;
|
|
224
|
-
var RadioGroupContext =
|
|
224
|
+
var RadioGroupContext = React5.createContext(null);
|
|
225
225
|
var useRadioGroup = () => {
|
|
226
|
-
const context =
|
|
226
|
+
const context = React5.useContext(RadioGroupContext);
|
|
227
227
|
return context;
|
|
228
228
|
};
|
|
229
229
|
function RadioGroup({
|
|
@@ -269,7 +269,8 @@ function Radio({
|
|
|
269
269
|
success: "border-success focus:ring-success",
|
|
270
270
|
warning: "border-warning focus:ring-warning"
|
|
271
271
|
};
|
|
272
|
-
const
|
|
272
|
+
const generatedId = React5.useId();
|
|
273
|
+
const inputId = id || `radio-${value || generatedId}`;
|
|
273
274
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
274
275
|
"div",
|
|
275
276
|
{
|
|
@@ -283,7 +284,7 @@ function Radio({
|
|
|
283
284
|
onChange: handleChange,
|
|
284
285
|
disabled,
|
|
285
286
|
"aria-label": ariaLabel,
|
|
286
|
-
"aria-invalid": validationState === "error",
|
|
287
|
+
"aria-invalid": validationState === "error" ? "true" : void 0,
|
|
287
288
|
id: inputId,
|
|
288
289
|
name,
|
|
289
290
|
value,
|
|
@@ -367,13 +368,13 @@ function MultiSelect({
|
|
|
367
368
|
size = "md",
|
|
368
369
|
className = ""
|
|
369
370
|
}) {
|
|
370
|
-
const [isOpen, setIsOpen] =
|
|
371
|
-
const [searchQuery, setSearchQuery] =
|
|
372
|
-
const [focusedIndex, setFocusedIndex] =
|
|
373
|
-
const containerRef =
|
|
374
|
-
const searchInputRef =
|
|
371
|
+
const [isOpen, setIsOpen] = React5.useState(false);
|
|
372
|
+
const [searchQuery, setSearchQuery] = React5.useState("");
|
|
373
|
+
const [focusedIndex, setFocusedIndex] = React5.useState(-1);
|
|
374
|
+
const containerRef = React5.useRef(null);
|
|
375
|
+
const searchInputRef = React5.useRef(null);
|
|
375
376
|
const selectedValues = value || [];
|
|
376
|
-
|
|
377
|
+
React5.useEffect(() => {
|
|
377
378
|
const handleClickOutside = (event) => {
|
|
378
379
|
if (containerRef.current && !containerRef.current.contains(event.target)) {
|
|
379
380
|
setIsOpen(false);
|
|
@@ -386,7 +387,7 @@ function MultiSelect({
|
|
|
386
387
|
}
|
|
387
388
|
return void 0;
|
|
388
389
|
}, [isOpen]);
|
|
389
|
-
|
|
390
|
+
React5.useEffect(() => {
|
|
390
391
|
if (isOpen && searchInputRef.current) {
|
|
391
392
|
searchInputRef.current.focus();
|
|
392
393
|
}
|
|
@@ -479,7 +480,13 @@ function MultiSelect({
|
|
|
479
480
|
selectedValues.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: getSelectedLabels().map((label, index) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
480
481
|
"span",
|
|
481
482
|
{
|
|
482
|
-
className: `
|
|
483
|
+
className: `
|
|
484
|
+
inline-flex items-center gap-1
|
|
485
|
+
bg-primary/10 text-primary rounded-md font-medium
|
|
486
|
+
animate-scaleIn origin-left
|
|
487
|
+
transition-all duration-200
|
|
488
|
+
${currentSize.chip}
|
|
489
|
+
`.trim(),
|
|
483
490
|
children: [
|
|
484
491
|
label,
|
|
485
492
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -487,7 +494,7 @@ function MultiSelect({
|
|
|
487
494
|
{
|
|
488
495
|
type: "button",
|
|
489
496
|
onClick: (e) => handleRemoveValue(selectedValues[index], e),
|
|
490
|
-
className: "hover:bg-primary/20 rounded-sm transition-colors",
|
|
497
|
+
className: "hover:bg-primary/20 rounded-sm transition-colors duration-150",
|
|
491
498
|
"aria-label": `Remove ${label}`,
|
|
492
499
|
tabIndex: -1,
|
|
493
500
|
children: /* @__PURE__ */ jsxRuntime.jsx(iconsReact.IconX, { size: currentSize.icon - 4 })
|
|
@@ -547,7 +554,7 @@ function MultiSelect({
|
|
|
547
554
|
onClick: () => !isDisabled && handleToggleOption(option.value),
|
|
548
555
|
className: `
|
|
549
556
|
w-full px-3 py-2 flex items-center justify-between gap-2
|
|
550
|
-
transition-
|
|
557
|
+
transition-all duration-200 text-left ${currentSize.text}
|
|
551
558
|
${isFocused ? "bg-muted" : ""}
|
|
552
559
|
${isSelected ? "bg-primary/10 text-primary font-medium" : "hover:bg-muted"}
|
|
553
560
|
${isDisabled ? "opacity-50 cursor-not-allowed" : ""}
|
|
@@ -557,7 +564,13 @@ function MultiSelect({
|
|
|
557
564
|
disabled: isDisabled,
|
|
558
565
|
children: [
|
|
559
566
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 truncate", children: option.label }),
|
|
560
|
-
isSelected && /* @__PURE__ */ jsxRuntime.jsx(
|
|
567
|
+
isSelected && /* @__PURE__ */ jsxRuntime.jsx(
|
|
568
|
+
iconsReact.IconCheck,
|
|
569
|
+
{
|
|
570
|
+
size: currentSize.icon,
|
|
571
|
+
className: "flex-shrink-0 animate-scaleIn"
|
|
572
|
+
}
|
|
573
|
+
)
|
|
561
574
|
]
|
|
562
575
|
},
|
|
563
576
|
option.value
|
|
@@ -870,7 +883,7 @@ function FormField({
|
|
|
870
883
|
validationState = "default"
|
|
871
884
|
}) {
|
|
872
885
|
const effectiveValidationState = error ? "error" : validationState;
|
|
873
|
-
const childWithValidation =
|
|
886
|
+
const childWithValidation = React5.isValidElement(children) ? React5.cloneElement(children, {
|
|
874
887
|
validationState: effectiveValidationState
|
|
875
888
|
}) : children;
|
|
876
889
|
return /* @__PURE__ */ jsxRuntime.jsxs(stack_default, { direction: "vertical", spacing: "sm", className, children: [
|
|
@@ -886,17 +899,42 @@ function FormField({
|
|
|
886
899
|
FormField.displayName = "FormField";
|
|
887
900
|
var form_field_default = FormField;
|
|
888
901
|
function InputGroup({ children, prefix, suffix, className = "" }) {
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
902
|
+
const isTextSuffix = typeof suffix === "string" || typeof suffix === "number";
|
|
903
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
904
|
+
"div",
|
|
905
|
+
{
|
|
906
|
+
className: [
|
|
907
|
+
"inline-flex items-stretch rounded-lg border border-input shadow-sm bg-background",
|
|
908
|
+
"focus-within:ring-2 focus-within:ring-ring/20 focus-within:border-ring",
|
|
909
|
+
"transition-colors duration-150 overflow-hidden",
|
|
910
|
+
// Use CSS nesting to style child input without cloning
|
|
911
|
+
"[&>input]:border-0 [&>input]:shadow-none [&>input]:rounded-none [&>input]:ring-0",
|
|
912
|
+
"[&>input]:focus:ring-0 [&>input]:focus:border-0 [&>input]:bg-transparent",
|
|
913
|
+
"[&>input]:flex-1 [&>input]:min-w-0",
|
|
914
|
+
// Style child buttons (both direct and nested)
|
|
915
|
+
"[&_button]:rounded-none [&_button]:border-0 [&_button]:shadow-none [&_button]:m-0",
|
|
916
|
+
"[&_button]:h-full",
|
|
917
|
+
className
|
|
918
|
+
].filter(Boolean).join(" "),
|
|
919
|
+
children: [
|
|
920
|
+
prefix && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center px-3 bg-muted/50 text-muted-foreground text-sm shrink-0", children: prefix }),
|
|
921
|
+
children,
|
|
922
|
+
suffix && /* @__PURE__ */ jsxRuntime.jsx(
|
|
923
|
+
"div",
|
|
924
|
+
{
|
|
925
|
+
className: isTextSuffix ? "flex items-center px-3 bg-muted/50 text-muted-foreground text-sm shrink-0" : "flex items-stretch shrink-0",
|
|
926
|
+
children: suffix
|
|
927
|
+
}
|
|
928
|
+
)
|
|
929
|
+
]
|
|
930
|
+
}
|
|
931
|
+
);
|
|
894
932
|
}
|
|
895
933
|
InputGroup.displayName = "InputGroup";
|
|
896
934
|
var input_group_default = InputGroup;
|
|
897
935
|
function Calendar({ value, onChange, minDate, maxDate, disabled = false, className = "" }) {
|
|
898
|
-
const [currentMonth, setCurrentMonth] =
|
|
899
|
-
const [selectedDate, setSelectedDate] =
|
|
936
|
+
const [currentMonth, setCurrentMonth] = React5.useState(value || /* @__PURE__ */ new Date());
|
|
937
|
+
const [selectedDate, setSelectedDate] = React5.useState(value);
|
|
900
938
|
const getDaysInMonth = (date) => {
|
|
901
939
|
return new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate();
|
|
902
940
|
};
|
|
@@ -1032,14 +1070,14 @@ function DatePicker({
|
|
|
1032
1070
|
className = "",
|
|
1033
1071
|
size = "md"
|
|
1034
1072
|
}) {
|
|
1035
|
-
const [isOpen, setIsOpen] =
|
|
1036
|
-
const [selectedDate, setSelectedDate] =
|
|
1037
|
-
const containerRef =
|
|
1038
|
-
const inputRef =
|
|
1039
|
-
|
|
1073
|
+
const [isOpen, setIsOpen] = React5.useState(false);
|
|
1074
|
+
const [selectedDate, setSelectedDate] = React5.useState(value);
|
|
1075
|
+
const containerRef = React5.useRef(null);
|
|
1076
|
+
const inputRef = React5.useRef(null);
|
|
1077
|
+
React5.useEffect(() => {
|
|
1040
1078
|
setSelectedDate(value);
|
|
1041
1079
|
}, [value]);
|
|
1042
|
-
|
|
1080
|
+
React5.useEffect(() => {
|
|
1043
1081
|
const handleClickOutside = (event) => {
|
|
1044
1082
|
if (containerRef.current && !containerRef.current.contains(event.target)) {
|
|
1045
1083
|
setIsOpen(false);
|
|
@@ -1051,7 +1089,7 @@ function DatePicker({
|
|
|
1051
1089
|
}
|
|
1052
1090
|
return void 0;
|
|
1053
1091
|
}, [isOpen]);
|
|
1054
|
-
|
|
1092
|
+
React5.useEffect(() => {
|
|
1055
1093
|
const handleEscape = (event) => {
|
|
1056
1094
|
if (event.key === "Escape" && isOpen) {
|
|
1057
1095
|
setIsOpen(false);
|
|
@@ -1182,8 +1220,31 @@ function DatePicker({
|
|
|
1182
1220
|
}
|
|
1183
1221
|
DatePicker.displayName = "DatePicker";
|
|
1184
1222
|
var date_picker_default = DatePicker;
|
|
1185
|
-
function Nav({
|
|
1186
|
-
|
|
1223
|
+
function Nav({
|
|
1224
|
+
children,
|
|
1225
|
+
className = "",
|
|
1226
|
+
ariaLabel = "Main navigation",
|
|
1227
|
+
direction = "horizontal",
|
|
1228
|
+
spacing = "md",
|
|
1229
|
+
align = "center"
|
|
1230
|
+
}) {
|
|
1231
|
+
const spacingClasses = {
|
|
1232
|
+
none: "gap-0",
|
|
1233
|
+
sm: "gap-2",
|
|
1234
|
+
md: "gap-4",
|
|
1235
|
+
lg: "gap-6",
|
|
1236
|
+
xl: "gap-8"
|
|
1237
|
+
};
|
|
1238
|
+
const alignClasses = {
|
|
1239
|
+
start: "items-start",
|
|
1240
|
+
center: "items-center",
|
|
1241
|
+
end: "items-end",
|
|
1242
|
+
stretch: "items-stretch"
|
|
1243
|
+
};
|
|
1244
|
+
const directionClass = direction === "horizontal" ? "flex-row" : "flex-col";
|
|
1245
|
+
const spacingClass = spacingClasses[spacing];
|
|
1246
|
+
const alignClass = alignClasses[align];
|
|
1247
|
+
return /* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-label": ariaLabel, className: `flex ${directionClass} ${spacingClass} ${alignClass} ${className}`, children });
|
|
1187
1248
|
}
|
|
1188
1249
|
Nav.displayName = "Nav";
|
|
1189
1250
|
var nav_default = Nav;
|
|
@@ -1192,7 +1253,9 @@ function Container({
|
|
|
1192
1253
|
className = "",
|
|
1193
1254
|
size = "lg",
|
|
1194
1255
|
padding = "lg",
|
|
1195
|
-
align = "center"
|
|
1256
|
+
align = "center",
|
|
1257
|
+
minWidth,
|
|
1258
|
+
minHeight
|
|
1196
1259
|
}) {
|
|
1197
1260
|
const sizeClasses = {
|
|
1198
1261
|
sm: "max-w-screen-sm",
|
|
@@ -1213,7 +1276,54 @@ function Container({
|
|
|
1213
1276
|
center: "mx-auto",
|
|
1214
1277
|
end: "ml-auto"
|
|
1215
1278
|
};
|
|
1216
|
-
|
|
1279
|
+
const minWidthClasses = {
|
|
1280
|
+
xs: "min-w-[20rem]",
|
|
1281
|
+
// 320px
|
|
1282
|
+
sm: "min-w-[24rem]",
|
|
1283
|
+
// 384px
|
|
1284
|
+
md: "min-w-[28rem]",
|
|
1285
|
+
// 448px
|
|
1286
|
+
lg: "min-w-[32rem]",
|
|
1287
|
+
// 512px
|
|
1288
|
+
xl: "min-w-[36rem]",
|
|
1289
|
+
// 576px
|
|
1290
|
+
"2xl": "min-w-[42rem]",
|
|
1291
|
+
// 672px
|
|
1292
|
+
"3xl": "min-w-[48rem]",
|
|
1293
|
+
// 768px
|
|
1294
|
+
full: "min-w-full"
|
|
1295
|
+
};
|
|
1296
|
+
const minHeightClasses = {
|
|
1297
|
+
xs: "min-h-[10rem]",
|
|
1298
|
+
// 160px
|
|
1299
|
+
sm: "min-h-[15rem]",
|
|
1300
|
+
// 240px
|
|
1301
|
+
md: "min-h-[20rem]",
|
|
1302
|
+
// 320px
|
|
1303
|
+
lg: "min-h-[25rem]",
|
|
1304
|
+
// 400px
|
|
1305
|
+
xl: "min-h-[30rem]",
|
|
1306
|
+
// 480px
|
|
1307
|
+
"2xl": "min-h-[35rem]",
|
|
1308
|
+
// 560px
|
|
1309
|
+
"3xl": "min-h-[40rem]",
|
|
1310
|
+
// 640px
|
|
1311
|
+
screen: "min-h-screen"
|
|
1312
|
+
};
|
|
1313
|
+
const minWidthClass = minWidth && minWidthClasses[minWidth] ? minWidthClasses[minWidth] : "";
|
|
1314
|
+
const minHeightClass = minHeight && minHeightClasses[minHeight] ? minHeightClasses[minHeight] : "";
|
|
1315
|
+
const inlineStyles = {
|
|
1316
|
+
...minWidth && !minWidthClasses[minWidth] && { minWidth },
|
|
1317
|
+
...minHeight && !minHeightClasses[minHeight] && { minHeight }
|
|
1318
|
+
};
|
|
1319
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1320
|
+
"div",
|
|
1321
|
+
{
|
|
1322
|
+
className: `px-4 ${sizeClasses[size]} ${paddingClasses[padding]} ${alignClasses[align]} ${minWidthClass} ${minHeightClass} ${className}`,
|
|
1323
|
+
style: Object.keys(inlineStyles).length > 0 ? inlineStyles : void 0,
|
|
1324
|
+
children
|
|
1325
|
+
}
|
|
1326
|
+
);
|
|
1217
1327
|
}
|
|
1218
1328
|
Container.displayName = "Container";
|
|
1219
1329
|
var container_default = Container;
|
|
@@ -1228,7 +1338,7 @@ function Navbar({
|
|
|
1228
1338
|
border = "none",
|
|
1229
1339
|
disableMobileMenu = false
|
|
1230
1340
|
}) {
|
|
1231
|
-
const [mobileMenuOpen, setMobileMenuOpen] =
|
|
1341
|
+
const [mobileMenuOpen, setMobileMenuOpen] = React5.useState(false);
|
|
1232
1342
|
const appearanceClasses = {
|
|
1233
1343
|
solid: "bg-background shadow-sm",
|
|
1234
1344
|
blur: "bg-background/70 backdrop-blur-md supports-[backdrop-filter]:bg-background/60 border border-border/60",
|
|
@@ -1323,8 +1433,8 @@ var PageTransition = ({
|
|
|
1323
1433
|
type = "fade",
|
|
1324
1434
|
className = ""
|
|
1325
1435
|
}) => {
|
|
1326
|
-
const [isVisible, setIsVisible] =
|
|
1327
|
-
|
|
1436
|
+
const [isVisible, setIsVisible] = React5__default.default.useState(false);
|
|
1437
|
+
React5__default.default.useEffect(() => {
|
|
1328
1438
|
requestAnimationFrame(() => {
|
|
1329
1439
|
requestAnimationFrame(() => {
|
|
1330
1440
|
setIsVisible(true);
|
|
@@ -1355,7 +1465,7 @@ var PageTransition = ({
|
|
|
1355
1465
|
PageTransition.displayName = "PageTransition";
|
|
1356
1466
|
var page_transition_default = PageTransition;
|
|
1357
1467
|
function Tabs({ tabs, defaultTab, className = "", ariaLabel = "Tabs" }) {
|
|
1358
|
-
const [activeTab, setActiveTab] =
|
|
1468
|
+
const [activeTab, setActiveTab] = React5.useState(defaultTab || tabs[0]?.id);
|
|
1359
1469
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, children: [
|
|
1360
1470
|
/* @__PURE__ */ jsxRuntime.jsx("div", { role: "tablist", "aria-label": ariaLabel, className: "flex border-b-2 border-border/50", children: tabs.map((tab) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1361
1471
|
"button",
|
|
@@ -1385,7 +1495,7 @@ function Tabs({ tabs, defaultTab, className = "", ariaLabel = "Tabs" }) {
|
|
|
1385
1495
|
}
|
|
1386
1496
|
Tabs.displayName = "Tabs";
|
|
1387
1497
|
var tabs_default = Tabs;
|
|
1388
|
-
var DropdownContext =
|
|
1498
|
+
var DropdownContext = React5.createContext(null);
|
|
1389
1499
|
function Dropdown({
|
|
1390
1500
|
trigger,
|
|
1391
1501
|
children,
|
|
@@ -1394,14 +1504,14 @@ function Dropdown({
|
|
|
1394
1504
|
autoClose = true,
|
|
1395
1505
|
size = "md"
|
|
1396
1506
|
}) {
|
|
1397
|
-
const [isOpen, setIsOpen] =
|
|
1398
|
-
const dropdownRef =
|
|
1399
|
-
const menuRef =
|
|
1400
|
-
const itemsRef =
|
|
1401
|
-
const [activeIndex, setActiveIndex] =
|
|
1402
|
-
const close =
|
|
1403
|
-
const open =
|
|
1404
|
-
|
|
1507
|
+
const [isOpen, setIsOpen] = React5.useState(false);
|
|
1508
|
+
const dropdownRef = React5.useRef(null);
|
|
1509
|
+
const menuRef = React5.useRef(null);
|
|
1510
|
+
const itemsRef = React5.useRef([]);
|
|
1511
|
+
const [activeIndex, setActiveIndex] = React5.useState(-1);
|
|
1512
|
+
const close = React5.useCallback(() => setIsOpen(false), []);
|
|
1513
|
+
const open = React5.useCallback(() => setIsOpen(true), []);
|
|
1514
|
+
React5.useEffect(() => {
|
|
1405
1515
|
if (!isOpen) return;
|
|
1406
1516
|
const handleKey = (e) => {
|
|
1407
1517
|
if (!menuRef.current) return;
|
|
@@ -1436,7 +1546,7 @@ function Dropdown({
|
|
|
1436
1546
|
document.addEventListener("keydown", handleKey);
|
|
1437
1547
|
return () => document.removeEventListener("keydown", handleKey);
|
|
1438
1548
|
}, [isOpen, activeIndex, close]);
|
|
1439
|
-
|
|
1549
|
+
React5.useEffect(() => {
|
|
1440
1550
|
if (!isOpen) return;
|
|
1441
1551
|
const handleClickOutside = (event) => {
|
|
1442
1552
|
if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
|
|
@@ -1446,20 +1556,34 @@ function Dropdown({
|
|
|
1446
1556
|
document.addEventListener("mousedown", handleClickOutside);
|
|
1447
1557
|
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
1448
1558
|
}, [isOpen, close]);
|
|
1449
|
-
|
|
1559
|
+
React5.useLayoutEffect(() => {
|
|
1560
|
+
let raf;
|
|
1450
1561
|
if (isOpen) {
|
|
1451
1562
|
const itemEls = itemsRef.current.filter(Boolean);
|
|
1452
1563
|
if (itemEls.length) {
|
|
1453
|
-
|
|
1454
|
-
|
|
1564
|
+
raf = requestAnimationFrame(() => {
|
|
1565
|
+
setActiveIndex(0);
|
|
1566
|
+
itemEls[0]?.focus();
|
|
1567
|
+
});
|
|
1455
1568
|
}
|
|
1456
1569
|
} else {
|
|
1457
|
-
setActiveIndex(-1);
|
|
1570
|
+
raf = requestAnimationFrame(() => setActiveIndex(-1));
|
|
1458
1571
|
}
|
|
1572
|
+
return () => {
|
|
1573
|
+
if (raf) cancelAnimationFrame(raf);
|
|
1574
|
+
};
|
|
1459
1575
|
}, [isOpen]);
|
|
1460
|
-
const registerItem = (el, index) => {
|
|
1461
|
-
|
|
1462
|
-
|
|
1576
|
+
const registerItem = React5.useCallback((el, index) => {
|
|
1577
|
+
if (typeof index === "number" && index >= 0) {
|
|
1578
|
+
itemsRef.current[index] = el;
|
|
1579
|
+
return;
|
|
1580
|
+
}
|
|
1581
|
+
if (el === null) {
|
|
1582
|
+
itemsRef.current = itemsRef.current.filter((x) => x !== el && x != null);
|
|
1583
|
+
return;
|
|
1584
|
+
}
|
|
1585
|
+
if (!itemsRef.current.includes(el)) itemsRef.current.push(el);
|
|
1586
|
+
}, []);
|
|
1463
1587
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: dropdownRef, className: `relative ${className}`, children: [
|
|
1464
1588
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1465
1589
|
"button",
|
|
@@ -1474,7 +1598,7 @@ function Dropdown({
|
|
|
1474
1598
|
children: trigger
|
|
1475
1599
|
}
|
|
1476
1600
|
),
|
|
1477
|
-
isOpen && /* @__PURE__ */ jsxRuntime.jsx(DropdownContext.Provider, { value: { requestClose: close, autoClose }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1601
|
+
isOpen && /* @__PURE__ */ jsxRuntime.jsx(DropdownContext.Provider, { value: { requestClose: close, autoClose, registerItem }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1478
1602
|
"div",
|
|
1479
1603
|
{
|
|
1480
1604
|
id: "dropdown-menu",
|
|
@@ -1483,10 +1607,7 @@ function Dropdown({
|
|
|
1483
1607
|
role: "menu",
|
|
1484
1608
|
"aria-orientation": "vertical",
|
|
1485
1609
|
tabIndex: -1,
|
|
1486
|
-
children
|
|
1487
|
-
if (!React3__default.default.isValidElement(child)) return child;
|
|
1488
|
-
return React3__default.default.cloneElement(child, { __dropdownIndex: i, __registerItem: registerItem, size });
|
|
1489
|
-
})
|
|
1610
|
+
children
|
|
1490
1611
|
}
|
|
1491
1612
|
) })
|
|
1492
1613
|
] });
|
|
@@ -1582,6 +1703,22 @@ Pagination.displayName = "Pagination";
|
|
|
1582
1703
|
var pagination_default = Pagination;
|
|
1583
1704
|
function Sidebar({ children, className = "", width = "16rem" }) {
|
|
1584
1705
|
const widthClass = width === "16rem" ? "w-64" : width === "4rem" ? "w-16" : "";
|
|
1706
|
+
const enhancedChildren = React5__default.default.Children.map(children, (child) => {
|
|
1707
|
+
if (!React5__default.default.isValidElement(child)) return child;
|
|
1708
|
+
const childProps = child.props || {};
|
|
1709
|
+
if ("href" in childProps) {
|
|
1710
|
+
const existing = typeof childProps.className === "string" ? childProps.className : "";
|
|
1711
|
+
const sidebarItemClasses = "flex items-center w-full justify-start gap-2 px-2 py-1.5 rounded hover:bg-muted";
|
|
1712
|
+
const childInner = child.props.children;
|
|
1713
|
+
const wrappedChildren = /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex items-center gap-2", children: childInner });
|
|
1714
|
+
const newProps = {
|
|
1715
|
+
...child.props,
|
|
1716
|
+
className: `${existing} ${sidebarItemClasses}`.trim()
|
|
1717
|
+
};
|
|
1718
|
+
return React5__default.default.cloneElement(child, newProps, wrappedChildren);
|
|
1719
|
+
}
|
|
1720
|
+
return child;
|
|
1721
|
+
});
|
|
1585
1722
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1586
1723
|
"nav",
|
|
1587
1724
|
{
|
|
@@ -1594,7 +1731,7 @@ function Sidebar({ children, className = "", width = "16rem" }) {
|
|
|
1594
1731
|
`.replace(/\s+/g, " "),
|
|
1595
1732
|
style: !widthClass ? { width } : void 0,
|
|
1596
1733
|
"aria-label": "Sidebar navigation",
|
|
1597
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 px-4 py-3
|
|
1734
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 px-4 py-3 flex flex-col gap-2", children: enhancedChildren })
|
|
1598
1735
|
}
|
|
1599
1736
|
);
|
|
1600
1737
|
}
|
|
@@ -1755,14 +1892,20 @@ function Stepper({
|
|
|
1755
1892
|
Stepper.displayName = "Stepper";
|
|
1756
1893
|
var stepper_default = Stepper;
|
|
1757
1894
|
function Toast({ message, children, type = "info", onClose, className = "", duration = 5e3 }) {
|
|
1758
|
-
const [isClosing, setIsClosing] =
|
|
1895
|
+
const [isClosing, setIsClosing] = React5.useState(false);
|
|
1759
1896
|
const typeClasses = {
|
|
1760
1897
|
info: "bg-info text-info-foreground",
|
|
1761
1898
|
success: "bg-success text-success-foreground",
|
|
1762
1899
|
warning: "bg-warning text-warning-foreground",
|
|
1763
1900
|
error: "bg-destructive text-destructive-foreground"
|
|
1764
1901
|
};
|
|
1765
|
-
|
|
1902
|
+
const handleClose = React5.useCallback(() => {
|
|
1903
|
+
setIsClosing(true);
|
|
1904
|
+
setTimeout(() => {
|
|
1905
|
+
onClose?.();
|
|
1906
|
+
}, 300);
|
|
1907
|
+
}, [onClose]);
|
|
1908
|
+
React5.useEffect(() => {
|
|
1766
1909
|
if (duration > 0) {
|
|
1767
1910
|
const timer = setTimeout(() => {
|
|
1768
1911
|
handleClose();
|
|
@@ -1770,25 +1913,20 @@ function Toast({ message, children, type = "info", onClose, className = "", dura
|
|
|
1770
1913
|
return () => clearTimeout(timer);
|
|
1771
1914
|
}
|
|
1772
1915
|
return void 0;
|
|
1773
|
-
}, [duration]);
|
|
1774
|
-
const
|
|
1775
|
-
setIsClosing(true);
|
|
1776
|
-
setTimeout(() => {
|
|
1777
|
-
onClose?.();
|
|
1778
|
-
}, 300);
|
|
1779
|
-
};
|
|
1780
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1916
|
+
}, [duration, handleClose]);
|
|
1917
|
+
const toast = /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1781
1918
|
"div",
|
|
1782
1919
|
{
|
|
1783
1920
|
role: "alert",
|
|
1784
1921
|
"aria-live": "polite",
|
|
1785
|
-
className: `fixed bottom-4 right-4 px-4 py-3 rounded-md shadow-lg ${typeClasses[type]} transition-all duration-300 ease-out ${isClosing ? "opacity-0 translate-x-full" : "opacity-100 translate-x-0 animate-slideInRight"} ${className}`,
|
|
1922
|
+
className: `fixed bottom-4 right-4 px-4 py-3 rounded-md shadow-lg z-[9999] ${typeClasses[type]} transition-all duration-300 ease-out ${isClosing ? "opacity-0 translate-x-full" : "opacity-100 translate-x-0 animate-slideInRight"} ${className}`,
|
|
1786
1923
|
children: [
|
|
1787
1924
|
/* @__PURE__ */ jsxRuntime.jsx("span", { children: children || message }),
|
|
1788
1925
|
onClose && /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: handleClose, className: "ml-4 font-bold hover:opacity-70 transition-opacity", "aria-label": "Close", children: "\xD7" })
|
|
1789
1926
|
]
|
|
1790
1927
|
}
|
|
1791
1928
|
);
|
|
1929
|
+
return typeof document !== "undefined" ? reactDom.createPortal(toast, document.body) : toast;
|
|
1792
1930
|
}
|
|
1793
1931
|
Toast.displayName = "Toast";
|
|
1794
1932
|
var toast_default = Toast;
|
|
@@ -1801,11 +1939,11 @@ function Tooltip({
|
|
|
1801
1939
|
usePortal = false,
|
|
1802
1940
|
className = ""
|
|
1803
1941
|
}) {
|
|
1804
|
-
const [showTooltip, setShowTooltip] =
|
|
1805
|
-
const [tooltipPosition, setTooltipPosition] =
|
|
1806
|
-
const triggerRef =
|
|
1942
|
+
const [showTooltip, setShowTooltip] = React5.useState(false);
|
|
1943
|
+
const [tooltipPosition, setTooltipPosition] = React5.useState({ top: 0, left: 0 });
|
|
1944
|
+
const triggerRef = React5.useRef(null);
|
|
1807
1945
|
const isVisible = open || showTooltip;
|
|
1808
|
-
|
|
1946
|
+
React5.useEffect(() => {
|
|
1809
1947
|
if (usePortal && isVisible && triggerRef.current) {
|
|
1810
1948
|
const rect = triggerRef.current.getBoundingClientRect();
|
|
1811
1949
|
const positions = {
|
|
@@ -1914,6 +2052,19 @@ function Tooltip({
|
|
|
1914
2052
|
}
|
|
1915
2053
|
Tooltip.displayName = "Tooltip";
|
|
1916
2054
|
var tooltip_default = Tooltip;
|
|
2055
|
+
|
|
2056
|
+
// src/utils/portal.ts
|
|
2057
|
+
function getPortalRoot(id = "hydn-ui-portal") {
|
|
2058
|
+
if (typeof document === "undefined") return null;
|
|
2059
|
+
let root = document.getElementById(id);
|
|
2060
|
+
if (!root) {
|
|
2061
|
+
root = document.createElement("div");
|
|
2062
|
+
root.id = id;
|
|
2063
|
+
document.body.appendChild(root);
|
|
2064
|
+
}
|
|
2065
|
+
return root;
|
|
2066
|
+
}
|
|
2067
|
+
var portal_default = getPortalRoot;
|
|
1917
2068
|
function useOverlay(options) {
|
|
1918
2069
|
const {
|
|
1919
2070
|
isOpen,
|
|
@@ -1924,14 +2075,15 @@ function useOverlay(options) {
|
|
|
1924
2075
|
exitDuration = 300,
|
|
1925
2076
|
unmountOnExit = true
|
|
1926
2077
|
} = options;
|
|
1927
|
-
const previouslyFocusedRef =
|
|
1928
|
-
const containerRef =
|
|
1929
|
-
const [shouldRender, setShouldRender] =
|
|
1930
|
-
const [phase, setPhase] =
|
|
1931
|
-
|
|
1932
|
-
if (isOpen) {
|
|
2078
|
+
const previouslyFocusedRef = React5.useRef(null);
|
|
2079
|
+
const containerRef = React5.useRef(null);
|
|
2080
|
+
const [shouldRender, setShouldRender] = React5.useState(isOpen);
|
|
2081
|
+
const [phase, setPhase] = React5.useState("mount");
|
|
2082
|
+
React5.useLayoutEffect(() => {
|
|
2083
|
+
if (isOpen && !shouldRender) {
|
|
1933
2084
|
setShouldRender(true);
|
|
1934
2085
|
setPhase("mount");
|
|
2086
|
+
} else if (isOpen && shouldRender && phase === "mount") {
|
|
1935
2087
|
requestAnimationFrame(() => {
|
|
1936
2088
|
setPhase("animating-in");
|
|
1937
2089
|
let frame = 0;
|
|
@@ -1943,13 +2095,17 @@ function useOverlay(options) {
|
|
|
1943
2095
|
requestAnimationFrame(step);
|
|
1944
2096
|
}
|
|
1945
2097
|
};
|
|
1946
|
-
|
|
2098
|
+
if (animationFrames > 0) {
|
|
2099
|
+
requestAnimationFrame(step);
|
|
2100
|
+
} else {
|
|
2101
|
+
setPhase("visible");
|
|
2102
|
+
}
|
|
1947
2103
|
});
|
|
1948
|
-
} else if (!isOpen && shouldRender) {
|
|
2104
|
+
} else if (!isOpen && shouldRender && phase !== "animating-out") {
|
|
1949
2105
|
setPhase("animating-out");
|
|
1950
2106
|
}
|
|
1951
|
-
}, [isOpen, shouldRender, animationFrames]);
|
|
1952
|
-
|
|
2107
|
+
}, [isOpen, shouldRender, phase, animationFrames]);
|
|
2108
|
+
React5.useEffect(() => {
|
|
1953
2109
|
if (phase === "animating-out" && unmountOnExit) {
|
|
1954
2110
|
const timeout = setTimeout(() => {
|
|
1955
2111
|
setShouldRender(false);
|
|
@@ -1959,7 +2115,7 @@ function useOverlay(options) {
|
|
|
1959
2115
|
}
|
|
1960
2116
|
return void 0;
|
|
1961
2117
|
}, [phase, exitDuration, unmountOnExit]);
|
|
1962
|
-
|
|
2118
|
+
React5.useEffect(() => {
|
|
1963
2119
|
if (isOpen) {
|
|
1964
2120
|
if (typeof document !== "undefined") {
|
|
1965
2121
|
if (restoreFocus) previouslyFocusedRef.current = document.activeElement;
|
|
@@ -1975,7 +2131,7 @@ function useOverlay(options) {
|
|
|
1975
2131
|
}
|
|
1976
2132
|
};
|
|
1977
2133
|
}, [isOpen, lockScroll, restoreFocus]);
|
|
1978
|
-
|
|
2134
|
+
React5.useEffect(() => {
|
|
1979
2135
|
if (phase === "visible" && containerRef.current) {
|
|
1980
2136
|
const el = containerRef.current;
|
|
1981
2137
|
try {
|
|
@@ -1985,7 +2141,7 @@ function useOverlay(options) {
|
|
|
1985
2141
|
}
|
|
1986
2142
|
}
|
|
1987
2143
|
}, [phase]);
|
|
1988
|
-
const handleKeyDown =
|
|
2144
|
+
const handleKeyDown = React5.useCallback(
|
|
1989
2145
|
(e) => {
|
|
1990
2146
|
if (!focusTrap || phase !== "visible" || e.key !== "Tab" || !containerRef.current) return;
|
|
1991
2147
|
const node = containerRef.current;
|
|
@@ -2007,14 +2163,14 @@ function useOverlay(options) {
|
|
|
2007
2163
|
},
|
|
2008
2164
|
[focusTrap, phase]
|
|
2009
2165
|
);
|
|
2010
|
-
|
|
2166
|
+
React5.useEffect(() => {
|
|
2011
2167
|
if (focusTrap && phase === "visible") {
|
|
2012
2168
|
document.addEventListener("keydown", handleKeyDown);
|
|
2013
2169
|
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
2014
2170
|
}
|
|
2015
2171
|
return void 0;
|
|
2016
2172
|
}, [phase, focusTrap, handleKeyDown]);
|
|
2017
|
-
const getPhaseClass =
|
|
2173
|
+
const getPhaseClass = React5.useCallback(
|
|
2018
2174
|
(openClass, closedClass) => {
|
|
2019
2175
|
return phase === "animating-in" || phase === "visible" ? openClass : closedClass;
|
|
2020
2176
|
},
|
|
@@ -2033,7 +2189,8 @@ function Modal({
|
|
|
2033
2189
|
actions,
|
|
2034
2190
|
className = "",
|
|
2035
2191
|
ariaLabel,
|
|
2036
|
-
align = "center"
|
|
2192
|
+
align = "center",
|
|
2193
|
+
portalRoot = portal_default()
|
|
2037
2194
|
}) {
|
|
2038
2195
|
const {
|
|
2039
2196
|
phase,
|
|
@@ -2047,7 +2204,7 @@ function Modal({
|
|
|
2047
2204
|
animationFrames: 2,
|
|
2048
2205
|
restoreFocus: true
|
|
2049
2206
|
});
|
|
2050
|
-
|
|
2207
|
+
React5__default.default.useEffect(() => {
|
|
2051
2208
|
if (!isOpen) return;
|
|
2052
2209
|
const handleEscape = (e) => {
|
|
2053
2210
|
if (e.key === "Escape") {
|
|
@@ -2065,7 +2222,7 @@ function Modal({
|
|
|
2065
2222
|
const backdropOpacity = phase === "visible" || phase === "animating-in" ? "opacity-100" : "opacity-0 transition-opacity delay-50";
|
|
2066
2223
|
const hasStructured = title || description || content || actions;
|
|
2067
2224
|
const alignmentClasses = align === "center" ? "grid place-items-center" : "flex items-start justify-center pt-20";
|
|
2068
|
-
|
|
2225
|
+
const panel = /* @__PURE__ */ jsxRuntime.jsx(
|
|
2069
2226
|
"div",
|
|
2070
2227
|
{
|
|
2071
2228
|
"data-phase": phase,
|
|
@@ -2099,6 +2256,7 @@ function Modal({
|
|
|
2099
2256
|
)
|
|
2100
2257
|
}
|
|
2101
2258
|
);
|
|
2259
|
+
return portalRoot ? reactDom.createPortal(panel, portalRoot) : panel;
|
|
2102
2260
|
}
|
|
2103
2261
|
Modal.displayName = "Modal";
|
|
2104
2262
|
var modal_default = Modal;
|
|
@@ -2161,10 +2319,10 @@ function DeleteDialog({
|
|
|
2161
2319
|
DeleteDialog.displayName = "DeleteDialog";
|
|
2162
2320
|
var delete_dialog_default = DeleteDialog;
|
|
2163
2321
|
function Popover({ trigger, children, content, position = "bottom", className = "" }) {
|
|
2164
|
-
const [isOpen, setIsOpen] =
|
|
2165
|
-
const popoverRef =
|
|
2322
|
+
const [isOpen, setIsOpen] = React5.useState(false);
|
|
2323
|
+
const popoverRef = React5.useRef(null);
|
|
2166
2324
|
const triggerContent = children || trigger;
|
|
2167
|
-
|
|
2325
|
+
React5.useEffect(() => {
|
|
2168
2326
|
const handleClickOutside = (event) => {
|
|
2169
2327
|
if (popoverRef.current && !popoverRef.current.contains(event.target)) {
|
|
2170
2328
|
setIsOpen(false);
|
|
@@ -2215,12 +2373,13 @@ function Popover({ trigger, children, content, position = "bottom", className =
|
|
|
2215
2373
|
}
|
|
2216
2374
|
Popover.displayName = "Popover";
|
|
2217
2375
|
var popover_default = Popover;
|
|
2218
|
-
function Alert({ children, type = "info", dismissible = false, onClose, className = "" }) {
|
|
2376
|
+
function Alert({ children, type = "info", dismissible = false, onClose, className = "", position = "relative", duration = 0 }) {
|
|
2377
|
+
const [isClosing, setIsClosing] = React5.useState(false);
|
|
2219
2378
|
const typeClasses = {
|
|
2220
|
-
info: "bg-info/
|
|
2221
|
-
success: "bg-success/
|
|
2222
|
-
warning: "bg-warning/
|
|
2223
|
-
error: "bg-destructive/
|
|
2379
|
+
info: "bg-info/20 text-foreground border-info/50 backdrop-blur-sm",
|
|
2380
|
+
success: "bg-success/20 text-foreground border-success/50 backdrop-blur-sm",
|
|
2381
|
+
warning: "bg-warning/20 text-foreground border-warning/50 backdrop-blur-sm",
|
|
2382
|
+
error: "bg-destructive/20 text-foreground border-destructive/50 backdrop-blur-sm"
|
|
2224
2383
|
};
|
|
2225
2384
|
const iconClasses = {
|
|
2226
2385
|
info: "text-info",
|
|
@@ -2228,6 +2387,21 @@ function Alert({ children, type = "info", dismissible = false, onClose, classNam
|
|
|
2228
2387
|
warning: "text-warning",
|
|
2229
2388
|
error: "text-destructive"
|
|
2230
2389
|
};
|
|
2390
|
+
const handleClose = React5.useCallback(() => {
|
|
2391
|
+
setIsClosing(true);
|
|
2392
|
+
setTimeout(() => {
|
|
2393
|
+
onClose?.();
|
|
2394
|
+
}, 300);
|
|
2395
|
+
}, [onClose]);
|
|
2396
|
+
React5.useEffect(() => {
|
|
2397
|
+
if (duration > 0 && onClose) {
|
|
2398
|
+
const timer = setTimeout(() => {
|
|
2399
|
+
handleClose();
|
|
2400
|
+
}, duration);
|
|
2401
|
+
return () => clearTimeout(timer);
|
|
2402
|
+
}
|
|
2403
|
+
return void 0;
|
|
2404
|
+
}, [duration, onClose, handleClose]);
|
|
2231
2405
|
const icons = {
|
|
2232
2406
|
info: /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-5 h-5 flex-shrink-0", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2233
2407
|
"path",
|
|
@@ -2262,19 +2436,44 @@ function Alert({ children, type = "info", dismissible = false, onClose, classNam
|
|
|
2262
2436
|
}
|
|
2263
2437
|
) })
|
|
2264
2438
|
};
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2439
|
+
const positionClasses = {
|
|
2440
|
+
top: "fixed top-4 left-1/2 -translate-x-1/2 z-[9999] max-w-2xl w-full mx-4",
|
|
2441
|
+
bottom: "fixed bottom-4 left-1/2 -translate-x-1/2 z-[9999] max-w-2xl w-full mx-4",
|
|
2442
|
+
relative: ""
|
|
2443
|
+
};
|
|
2444
|
+
const getAnimationClasses = () => {
|
|
2445
|
+
if (position === "top") {
|
|
2446
|
+
return isClosing ? "opacity-0 -translate-y-full" : "opacity-100 translate-y-0 animate-slideInTop";
|
|
2447
|
+
}
|
|
2448
|
+
if (position === "bottom") {
|
|
2449
|
+
return isClosing ? "opacity-0 translate-y-full" : "opacity-100 translate-y-0 animate-slideInBottom";
|
|
2450
|
+
}
|
|
2451
|
+
return isClosing ? "opacity-0" : "opacity-100";
|
|
2452
|
+
};
|
|
2453
|
+
const alertContent = /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2454
|
+
"div",
|
|
2455
|
+
{
|
|
2456
|
+
role: "alert",
|
|
2457
|
+
className: `p-4 border rounded-lg flex items-start gap-3 transition-all duration-300 ease-out ${typeClasses[type]} ${positionClasses[position]} ${getAnimationClasses()} ${className}`,
|
|
2458
|
+
children: [
|
|
2459
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: iconClasses[type], children: icons[type] }),
|
|
2460
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 text-sm", children }),
|
|
2461
|
+
dismissible && onClose && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2462
|
+
"button",
|
|
2463
|
+
{
|
|
2464
|
+
onClick: handleClose,
|
|
2465
|
+
className: "flex-shrink-0 text-current opacity-70 hover:opacity-100 transition-opacity focus:outline-none focus:ring-2 focus:ring-ring rounded p-0.5",
|
|
2466
|
+
"aria-label": "Close alert",
|
|
2467
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
|
|
2468
|
+
}
|
|
2469
|
+
)
|
|
2470
|
+
]
|
|
2471
|
+
}
|
|
2472
|
+
);
|
|
2473
|
+
if (position !== "relative" && typeof document !== "undefined") {
|
|
2474
|
+
return reactDom.createPortal(alertContent, document.body);
|
|
2475
|
+
}
|
|
2476
|
+
return alertContent;
|
|
2278
2477
|
}
|
|
2279
2478
|
Alert.displayName = "Alert";
|
|
2280
2479
|
var alert_default = Alert;
|
|
@@ -2580,12 +2779,12 @@ function TableCell({ children, className = "", align = "left", ...props }) {
|
|
|
2580
2779
|
return /* @__PURE__ */ jsxRuntime.jsx("td", { className: `px-6 py-4 whitespace-nowrap ${alignClasses[align]} ${className}`, ...props, children });
|
|
2581
2780
|
}
|
|
2582
2781
|
function useTable({ data, initialSort, pageSize = 10 }) {
|
|
2583
|
-
const [sortConfig, setSortConfig] =
|
|
2782
|
+
const [sortConfig, setSortConfig] = React5.useState(
|
|
2584
2783
|
initialSort ? { key: initialSort.key, direction: initialSort.direction } : null
|
|
2585
2784
|
);
|
|
2586
|
-
const [currentPage, setCurrentPage] =
|
|
2587
|
-
const [selectedRows, setSelectedRows] =
|
|
2588
|
-
const sortedData =
|
|
2785
|
+
const [currentPage, setCurrentPage] = React5.useState(1);
|
|
2786
|
+
const [selectedRows, setSelectedRows] = React5.useState(/* @__PURE__ */ new Set());
|
|
2787
|
+
const sortedData = React5.useMemo(() => {
|
|
2589
2788
|
if (!sortConfig) return data;
|
|
2590
2789
|
const sorted = [...data].sort((a, b) => {
|
|
2591
2790
|
const aValue = a[sortConfig.key];
|
|
@@ -3061,7 +3260,7 @@ function Heading({ children, level = 1, className = "", noMargin = false }) {
|
|
|
3061
3260
|
6: "mb-2"
|
|
3062
3261
|
};
|
|
3063
3262
|
const margin = noMargin ? "" : marginClasses[level];
|
|
3064
|
-
return
|
|
3263
|
+
return React5.createElement(
|
|
3065
3264
|
`h${level}`,
|
|
3066
3265
|
{
|
|
3067
3266
|
className: `text-foreground ${levelClasses[level]} ${margin} ${className}`
|
|
@@ -3254,7 +3453,7 @@ function PricingTier({
|
|
|
3254
3453
|
PricingTier.displayName = "PricingTier";
|
|
3255
3454
|
var pricing_tier_default = PricingTier;
|
|
3256
3455
|
function CodeBlock({ code, className = "", showCopy = true }) {
|
|
3257
|
-
const [copied, setCopied] =
|
|
3456
|
+
const [copied, setCopied] = React5.useState(false);
|
|
3258
3457
|
const handleCopy = async () => {
|
|
3259
3458
|
try {
|
|
3260
3459
|
await navigator.clipboard.writeText(code);
|
|
@@ -3391,7 +3590,7 @@ function Drawer({
|
|
|
3391
3590
|
closeOnEscape = true,
|
|
3392
3591
|
closeOnOutside = true,
|
|
3393
3592
|
unmountOnExit = true,
|
|
3394
|
-
portalRoot =
|
|
3593
|
+
portalRoot = portal_default(),
|
|
3395
3594
|
noAnimation = false
|
|
3396
3595
|
}) {
|
|
3397
3596
|
const { phase, shouldRender, ref, getPhaseClass } = useOverlay_default({
|
|
@@ -3400,8 +3599,8 @@ function Drawer({
|
|
|
3400
3599
|
restoreFocus: true,
|
|
3401
3600
|
focusTrap: true,
|
|
3402
3601
|
unmountOnExit,
|
|
3403
|
-
exitDuration: noAnimation ? 0 :
|
|
3404
|
-
animationFrames: noAnimation ? 0 :
|
|
3602
|
+
exitDuration: noAnimation ? 0 : 250,
|
|
3603
|
+
animationFrames: noAnimation ? 0 : 0
|
|
3405
3604
|
});
|
|
3406
3605
|
if (!shouldRender) return null;
|
|
3407
3606
|
const sizeClasses = {
|
|
@@ -3425,7 +3624,7 @@ function Drawer({
|
|
|
3425
3624
|
};
|
|
3426
3625
|
const openTransform = "translate-x-0 translate-y-0";
|
|
3427
3626
|
const panelTransform = noAnimation ? "" : getPhaseClass(openTransform, closedTransform[position]);
|
|
3428
|
-
const overlayOpacity = noAnimation ? "" : getPhaseClass("opacity-100", "opacity-0");
|
|
3627
|
+
const overlayOpacity = noAnimation ? "opacity-100" : getPhaseClass("opacity-100", "opacity-0");
|
|
3429
3628
|
const handleKeyDown = (e) => {
|
|
3430
3629
|
if (e.key === "Escape" && closeOnEscape) {
|
|
3431
3630
|
e.stopPropagation();
|
|
@@ -3434,11 +3633,21 @@ function Drawer({
|
|
|
3434
3633
|
};
|
|
3435
3634
|
const panel = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3436
3635
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3437
|
-
"
|
|
3636
|
+
"button",
|
|
3438
3637
|
{
|
|
3439
|
-
|
|
3440
|
-
|
|
3638
|
+
type: "button",
|
|
3639
|
+
className: `fixed inset-0 z-[999] bg-black/50 backdrop-blur-sm transition-opacity duration-[250ms] ease-in-out ${overlayOpacity} border-0 p-0 m-0`,
|
|
3640
|
+
"aria-label": closeOnOutside ? "Close overlay" : void 0,
|
|
3641
|
+
"aria-hidden": !closeOnOutside,
|
|
3642
|
+
tabIndex: closeOnOutside ? 0 : -1,
|
|
3441
3643
|
onClick: () => closeOnOutside && onClose(),
|
|
3644
|
+
onKeyDown: (e) => {
|
|
3645
|
+
if (!closeOnOutside) return;
|
|
3646
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
3647
|
+
e.preventDefault();
|
|
3648
|
+
onClose();
|
|
3649
|
+
}
|
|
3650
|
+
},
|
|
3442
3651
|
"data-phase": phase
|
|
3443
3652
|
}
|
|
3444
3653
|
),
|
|
@@ -3452,7 +3661,7 @@ function Drawer({
|
|
|
3452
3661
|
tabIndex: -1,
|
|
3453
3662
|
"data-phase": phase,
|
|
3454
3663
|
"data-position": position,
|
|
3455
|
-
className: `fixed ${edgeClasses[position]} ${position === "left" || position === "right" ? sizeClasses[size] : ""} bg-card text-card-foreground shadow-2xl z-
|
|
3664
|
+
className: `fixed ${edgeClasses[position]} ${position === "left" || position === "right" ? sizeClasses[size] : ""} bg-card text-card-foreground shadow-2xl z-[1000] flex flex-col outline-none ${panelTransform} ${noAnimation ? "" : "transition-transform duration-[250ms] ease-out will-change-transform"} ${className}`,
|
|
3456
3665
|
onKeyDown: handleKeyDown,
|
|
3457
3666
|
children: [
|
|
3458
3667
|
title && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-5 py-4 border-b border-border/60 bg-card/95 backdrop-blur-sm", children: [
|
|
@@ -3500,7 +3709,7 @@ function Page({ children, className = "" }) {
|
|
|
3500
3709
|
Page.displayName = "Page";
|
|
3501
3710
|
var page_default = Page;
|
|
3502
3711
|
function AccordionItem({ title, children, defaultOpen = false }) {
|
|
3503
|
-
const [isOpen, setIsOpen] =
|
|
3712
|
+
const [isOpen, setIsOpen] = React5.useState(defaultOpen);
|
|
3504
3713
|
return /* @__PURE__ */ jsxRuntime.jsxs("article", { className: "border-b border-border", children: [
|
|
3505
3714
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3506
3715
|
"button",
|
|
@@ -3728,14 +3937,18 @@ function Footer({ sections, copyright, social, className = "" }) {
|
|
|
3728
3937
|
Footer.displayName = "Footer";
|
|
3729
3938
|
var footer_default = Footer;
|
|
3730
3939
|
function useScrollReset(deps, container) {
|
|
3731
|
-
|
|
3940
|
+
React5.useEffect(() => {
|
|
3732
3941
|
let cancelled = false;
|
|
3733
3942
|
const maxRaf = 6;
|
|
3734
3943
|
let rafCount = 0;
|
|
3944
|
+
const isRef = (obj) => {
|
|
3945
|
+
return typeof obj === "object" && obj !== null && "current" in obj;
|
|
3946
|
+
};
|
|
3735
3947
|
const setAllScrollTop = () => {
|
|
3736
3948
|
if (cancelled) return;
|
|
3737
3949
|
window.scrollTo(0, 0);
|
|
3738
|
-
|
|
3950
|
+
const resolved = isRef(container) ? container.current : container;
|
|
3951
|
+
if (resolved) resolved.scrollTop = 0;
|
|
3739
3952
|
document.documentElement.scrollTop = 0;
|
|
3740
3953
|
document.body.scrollTop = 0;
|
|
3741
3954
|
};
|
|
@@ -3773,11 +3986,11 @@ function LeftNavLayout({
|
|
|
3773
3986
|
embedded = false,
|
|
3774
3987
|
mainContentRef
|
|
3775
3988
|
}) {
|
|
3776
|
-
const [internalCollapsed, setInternalCollapsed] =
|
|
3777
|
-
const [internalMobileMenuOpen, setInternalMobileMenuOpen] =
|
|
3778
|
-
const navRef =
|
|
3779
|
-
const scrollPosRef =
|
|
3780
|
-
const internalContentRef =
|
|
3989
|
+
const [internalCollapsed, setInternalCollapsed] = React5.useState(false);
|
|
3990
|
+
const [internalMobileMenuOpen, setInternalMobileMenuOpen] = React5.useState(false);
|
|
3991
|
+
const navRef = React5.useRef(null);
|
|
3992
|
+
const scrollPosRef = React5.useRef(0);
|
|
3993
|
+
const internalContentRef = React5.useRef(null);
|
|
3781
3994
|
const contentRef = mainContentRef || internalContentRef;
|
|
3782
3995
|
const collapsed = controlledCollapsed ?? internalCollapsed;
|
|
3783
3996
|
const setCollapsed = (value) => {
|
|
@@ -3797,12 +4010,12 @@ function LeftNavLayout({
|
|
|
3797
4010
|
};
|
|
3798
4011
|
const toggleCollapsed = () => setCollapsed(!collapsed);
|
|
3799
4012
|
const toggleMobileMenu = () => setMobileMenuOpen(!mobileMenuOpen);
|
|
3800
|
-
|
|
4013
|
+
React5.useEffect(() => {
|
|
3801
4014
|
if (navRef.current) {
|
|
3802
4015
|
navRef.current.scrollTop = scrollPosRef.current;
|
|
3803
4016
|
}
|
|
3804
4017
|
}, [children]);
|
|
3805
|
-
useScrollReset_default([children], contentRef
|
|
4018
|
+
useScrollReset_default([children], contentRef);
|
|
3806
4019
|
const containerClasses = embedded ? "flex bg-background border border-border rounded-lg overflow-hidden" : "flex h-[calc(100vh-4rem)] bg-background";
|
|
3807
4020
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${containerClasses} ${className}`, children: [
|
|
3808
4021
|
mobileCollapsible && mobileMenuOpen && /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -3834,17 +4047,34 @@ function LeftNavLayout({
|
|
|
3834
4047
|
"div",
|
|
3835
4048
|
{
|
|
3836
4049
|
className: `
|
|
3837
|
-
flex items-center h-12 flex-shrink-0
|
|
4050
|
+
relative flex items-center h-12 flex-shrink-0
|
|
3838
4051
|
px-4 border-b border-border
|
|
3839
|
-
${collapsed ? "justify-center" : "justify-between"}
|
|
3840
4052
|
`,
|
|
3841
4053
|
children: [
|
|
3842
|
-
|
|
4054
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4055
|
+
"span",
|
|
4056
|
+
{
|
|
4057
|
+
className: `
|
|
4058
|
+
text-sm font-semibold text-foreground
|
|
4059
|
+
transition-all duration-300 ease-in-out
|
|
4060
|
+
${collapsed ? "opacity-0 w-0 overflow-hidden" : "opacity-100"}
|
|
4061
|
+
`,
|
|
4062
|
+
children: "Navigation"
|
|
4063
|
+
}
|
|
4064
|
+
),
|
|
3843
4065
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3844
4066
|
"button",
|
|
3845
4067
|
{
|
|
3846
4068
|
onClick: toggleCollapsed,
|
|
3847
|
-
className:
|
|
4069
|
+
className: `
|
|
4070
|
+
hidden lg:flex items-center justify-center
|
|
4071
|
+
w-8 h-8 rounded-md
|
|
4072
|
+
text-muted-foreground hover:text-foreground
|
|
4073
|
+
hover:bg-muted
|
|
4074
|
+
transition-all duration-300 ease-in-out
|
|
4075
|
+
focus:outline-none focus:ring-2 focus:ring-ring
|
|
4076
|
+
${collapsed ? "absolute left-1/2 -translate-x-1/2" : "absolute right-4"}
|
|
4077
|
+
`,
|
|
3848
4078
|
"aria-label": collapsed ? "Expand sidebar" : "Collapse sidebar",
|
|
3849
4079
|
type: "button",
|
|
3850
4080
|
children: collapsed ? /* @__PURE__ */ jsxRuntime.jsx(iconsReact.IconChevronRight, { size: 20 }) : /* @__PURE__ */ jsxRuntime.jsx(iconsReact.IconChevronLeft, { size: 20 })
|
|
@@ -3890,15 +4120,15 @@ function LeftNavItem({
|
|
|
3890
4120
|
title,
|
|
3891
4121
|
preventNavigation = false
|
|
3892
4122
|
}) {
|
|
3893
|
-
const navRef =
|
|
3894
|
-
const [isCollapsed, setIsCollapsed] =
|
|
4123
|
+
const navRef = React5.useRef(null);
|
|
4124
|
+
const [isCollapsed, setIsCollapsed] = React5.useState(() => {
|
|
3895
4125
|
if (typeof window !== "undefined") {
|
|
3896
4126
|
const navElement = document.querySelector("nav[data-collapsed]");
|
|
3897
4127
|
return navElement?.getAttribute("data-collapsed") === "true";
|
|
3898
4128
|
}
|
|
3899
4129
|
return false;
|
|
3900
4130
|
});
|
|
3901
|
-
|
|
4131
|
+
React5.useEffect(() => {
|
|
3902
4132
|
const checkCollapsed = () => {
|
|
3903
4133
|
const navElement2 = navRef.current?.closest("nav");
|
|
3904
4134
|
if (navElement2) {
|
|
@@ -4001,26 +4231,26 @@ function Code({ children, block = false, variant = "default", className = "" })
|
|
|
4001
4231
|
}
|
|
4002
4232
|
Code.displayName = "Code";
|
|
4003
4233
|
var code_default = Code;
|
|
4004
|
-
var ThemeContext =
|
|
4234
|
+
var ThemeContext = React5.createContext(void 0);
|
|
4005
4235
|
function ThemeProvider({
|
|
4006
4236
|
children,
|
|
4007
4237
|
defaultTheme = "light",
|
|
4008
4238
|
storageKey = "hydn-theme",
|
|
4009
4239
|
themes = ["light", "dark"]
|
|
4010
4240
|
}) {
|
|
4011
|
-
const [theme, setThemeState] =
|
|
4241
|
+
const [theme, setThemeState] = React5.useState(() => {
|
|
4012
4242
|
if (typeof window !== "undefined") {
|
|
4013
4243
|
const stored = localStorage.getItem(storageKey);
|
|
4014
4244
|
return stored && themes.includes(stored) ? stored : defaultTheme;
|
|
4015
4245
|
}
|
|
4016
4246
|
return defaultTheme;
|
|
4017
4247
|
});
|
|
4018
|
-
|
|
4248
|
+
React5.useEffect(() => {
|
|
4019
4249
|
const root = window.document.documentElement;
|
|
4020
4250
|
root.classList.remove(...themes);
|
|
4021
4251
|
root.classList.add(theme);
|
|
4022
4252
|
}, [theme, themes]);
|
|
4023
|
-
const setTheme =
|
|
4253
|
+
const setTheme = React5.useCallback(
|
|
4024
4254
|
(newTheme) => {
|
|
4025
4255
|
if (themes.includes(newTheme)) {
|
|
4026
4256
|
localStorage.setItem(storageKey, newTheme);
|
|
@@ -4031,7 +4261,7 @@ function ThemeProvider({
|
|
|
4031
4261
|
},
|
|
4032
4262
|
[themes, storageKey]
|
|
4033
4263
|
);
|
|
4034
|
-
const value =
|
|
4264
|
+
const value = React5.useMemo(
|
|
4035
4265
|
() => ({
|
|
4036
4266
|
theme,
|
|
4037
4267
|
setTheme,
|
|
@@ -4042,7 +4272,7 @@ function ThemeProvider({
|
|
|
4042
4272
|
return /* @__PURE__ */ jsxRuntime.jsx(ThemeContext.Provider, { value, children });
|
|
4043
4273
|
}
|
|
4044
4274
|
function useTheme() {
|
|
4045
|
-
const context =
|
|
4275
|
+
const context = React5.useContext(ThemeContext);
|
|
4046
4276
|
if (!context) {
|
|
4047
4277
|
throw new Error("useTheme must be used within a ThemeProvider");
|
|
4048
4278
|
}
|