@hyddenlabs/hydn-ui 0.3.0-alpha.2 → 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.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
2
|
-
import
|
|
2
|
+
import React5, { createContext, useId, useState, useRef, useEffect, isValidElement, cloneElement, useCallback, useLayoutEffect, useMemo, createElement, useContext } from 'react';
|
|
3
3
|
import { IconX, IconChevronDown, IconCheck, IconCalendar, IconMenu2, IconTrash, IconChevronRight, IconChevronLeft, IconSelector, IconChevronUp } from '@tabler/icons-react';
|
|
4
4
|
import { Link, NavLink } from 'react-router-dom';
|
|
5
5
|
import { createPortal } from 'react-dom';
|
|
@@ -263,7 +263,8 @@ function Radio({
|
|
|
263
263
|
success: "border-success focus:ring-success",
|
|
264
264
|
warning: "border-warning focus:ring-warning"
|
|
265
265
|
};
|
|
266
|
-
const
|
|
266
|
+
const generatedId = useId();
|
|
267
|
+
const inputId = id || `radio-${value || generatedId}`;
|
|
267
268
|
return /* @__PURE__ */ jsxs(
|
|
268
269
|
"div",
|
|
269
270
|
{
|
|
@@ -277,7 +278,7 @@ function Radio({
|
|
|
277
278
|
onChange: handleChange,
|
|
278
279
|
disabled,
|
|
279
280
|
"aria-label": ariaLabel,
|
|
280
|
-
"aria-invalid": validationState === "error",
|
|
281
|
+
"aria-invalid": validationState === "error" ? "true" : void 0,
|
|
281
282
|
id: inputId,
|
|
282
283
|
name,
|
|
283
284
|
value,
|
|
@@ -473,7 +474,13 @@ function MultiSelect({
|
|
|
473
474
|
selectedValues.length > 0 ? /* @__PURE__ */ jsx(Fragment, { children: getSelectedLabels().map((label, index) => /* @__PURE__ */ jsxs(
|
|
474
475
|
"span",
|
|
475
476
|
{
|
|
476
|
-
className: `
|
|
477
|
+
className: `
|
|
478
|
+
inline-flex items-center gap-1
|
|
479
|
+
bg-primary/10 text-primary rounded-md font-medium
|
|
480
|
+
animate-scaleIn origin-left
|
|
481
|
+
transition-all duration-200
|
|
482
|
+
${currentSize.chip}
|
|
483
|
+
`.trim(),
|
|
477
484
|
children: [
|
|
478
485
|
label,
|
|
479
486
|
/* @__PURE__ */ jsx(
|
|
@@ -481,7 +488,7 @@ function MultiSelect({
|
|
|
481
488
|
{
|
|
482
489
|
type: "button",
|
|
483
490
|
onClick: (e) => handleRemoveValue(selectedValues[index], e),
|
|
484
|
-
className: "hover:bg-primary/20 rounded-sm transition-colors",
|
|
491
|
+
className: "hover:bg-primary/20 rounded-sm transition-colors duration-150",
|
|
485
492
|
"aria-label": `Remove ${label}`,
|
|
486
493
|
tabIndex: -1,
|
|
487
494
|
children: /* @__PURE__ */ jsx(IconX, { size: currentSize.icon - 4 })
|
|
@@ -541,7 +548,7 @@ function MultiSelect({
|
|
|
541
548
|
onClick: () => !isDisabled && handleToggleOption(option.value),
|
|
542
549
|
className: `
|
|
543
550
|
w-full px-3 py-2 flex items-center justify-between gap-2
|
|
544
|
-
transition-
|
|
551
|
+
transition-all duration-200 text-left ${currentSize.text}
|
|
545
552
|
${isFocused ? "bg-muted" : ""}
|
|
546
553
|
${isSelected ? "bg-primary/10 text-primary font-medium" : "hover:bg-muted"}
|
|
547
554
|
${isDisabled ? "opacity-50 cursor-not-allowed" : ""}
|
|
@@ -551,7 +558,13 @@ function MultiSelect({
|
|
|
551
558
|
disabled: isDisabled,
|
|
552
559
|
children: [
|
|
553
560
|
/* @__PURE__ */ jsx("span", { className: "flex-1 truncate", children: option.label }),
|
|
554
|
-
isSelected && /* @__PURE__ */ jsx(
|
|
561
|
+
isSelected && /* @__PURE__ */ jsx(
|
|
562
|
+
IconCheck,
|
|
563
|
+
{
|
|
564
|
+
size: currentSize.icon,
|
|
565
|
+
className: "flex-shrink-0 animate-scaleIn"
|
|
566
|
+
}
|
|
567
|
+
)
|
|
555
568
|
]
|
|
556
569
|
},
|
|
557
570
|
option.value
|
|
@@ -880,11 +893,36 @@ function FormField({
|
|
|
880
893
|
FormField.displayName = "FormField";
|
|
881
894
|
var form_field_default = FormField;
|
|
882
895
|
function InputGroup({ children, prefix, suffix, className = "" }) {
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
896
|
+
const isTextSuffix = typeof suffix === "string" || typeof suffix === "number";
|
|
897
|
+
return /* @__PURE__ */ jsxs(
|
|
898
|
+
"div",
|
|
899
|
+
{
|
|
900
|
+
className: [
|
|
901
|
+
"inline-flex items-stretch rounded-lg border border-input shadow-sm bg-background",
|
|
902
|
+
"focus-within:ring-2 focus-within:ring-ring/20 focus-within:border-ring",
|
|
903
|
+
"transition-colors duration-150 overflow-hidden",
|
|
904
|
+
// Use CSS nesting to style child input without cloning
|
|
905
|
+
"[&>input]:border-0 [&>input]:shadow-none [&>input]:rounded-none [&>input]:ring-0",
|
|
906
|
+
"[&>input]:focus:ring-0 [&>input]:focus:border-0 [&>input]:bg-transparent",
|
|
907
|
+
"[&>input]:flex-1 [&>input]:min-w-0",
|
|
908
|
+
// Style child buttons (both direct and nested)
|
|
909
|
+
"[&_button]:rounded-none [&_button]:border-0 [&_button]:shadow-none [&_button]:m-0",
|
|
910
|
+
"[&_button]:h-full",
|
|
911
|
+
className
|
|
912
|
+
].filter(Boolean).join(" "),
|
|
913
|
+
children: [
|
|
914
|
+
prefix && /* @__PURE__ */ jsx("div", { className: "flex items-center px-3 bg-muted/50 text-muted-foreground text-sm shrink-0", children: prefix }),
|
|
915
|
+
children,
|
|
916
|
+
suffix && /* @__PURE__ */ jsx(
|
|
917
|
+
"div",
|
|
918
|
+
{
|
|
919
|
+
className: isTextSuffix ? "flex items-center px-3 bg-muted/50 text-muted-foreground text-sm shrink-0" : "flex items-stretch shrink-0",
|
|
920
|
+
children: suffix
|
|
921
|
+
}
|
|
922
|
+
)
|
|
923
|
+
]
|
|
924
|
+
}
|
|
925
|
+
);
|
|
888
926
|
}
|
|
889
927
|
InputGroup.displayName = "InputGroup";
|
|
890
928
|
var input_group_default = InputGroup;
|
|
@@ -1176,8 +1214,31 @@ function DatePicker({
|
|
|
1176
1214
|
}
|
|
1177
1215
|
DatePicker.displayName = "DatePicker";
|
|
1178
1216
|
var date_picker_default = DatePicker;
|
|
1179
|
-
function Nav({
|
|
1180
|
-
|
|
1217
|
+
function Nav({
|
|
1218
|
+
children,
|
|
1219
|
+
className = "",
|
|
1220
|
+
ariaLabel = "Main navigation",
|
|
1221
|
+
direction = "horizontal",
|
|
1222
|
+
spacing = "md",
|
|
1223
|
+
align = "center"
|
|
1224
|
+
}) {
|
|
1225
|
+
const spacingClasses = {
|
|
1226
|
+
none: "gap-0",
|
|
1227
|
+
sm: "gap-2",
|
|
1228
|
+
md: "gap-4",
|
|
1229
|
+
lg: "gap-6",
|
|
1230
|
+
xl: "gap-8"
|
|
1231
|
+
};
|
|
1232
|
+
const alignClasses = {
|
|
1233
|
+
start: "items-start",
|
|
1234
|
+
center: "items-center",
|
|
1235
|
+
end: "items-end",
|
|
1236
|
+
stretch: "items-stretch"
|
|
1237
|
+
};
|
|
1238
|
+
const directionClass = direction === "horizontal" ? "flex-row" : "flex-col";
|
|
1239
|
+
const spacingClass = spacingClasses[spacing];
|
|
1240
|
+
const alignClass = alignClasses[align];
|
|
1241
|
+
return /* @__PURE__ */ jsx("nav", { "aria-label": ariaLabel, className: `flex ${directionClass} ${spacingClass} ${alignClass} ${className}`, children });
|
|
1181
1242
|
}
|
|
1182
1243
|
Nav.displayName = "Nav";
|
|
1183
1244
|
var nav_default = Nav;
|
|
@@ -1186,7 +1247,9 @@ function Container({
|
|
|
1186
1247
|
className = "",
|
|
1187
1248
|
size = "lg",
|
|
1188
1249
|
padding = "lg",
|
|
1189
|
-
align = "center"
|
|
1250
|
+
align = "center",
|
|
1251
|
+
minWidth,
|
|
1252
|
+
minHeight
|
|
1190
1253
|
}) {
|
|
1191
1254
|
const sizeClasses = {
|
|
1192
1255
|
sm: "max-w-screen-sm",
|
|
@@ -1207,7 +1270,54 @@ function Container({
|
|
|
1207
1270
|
center: "mx-auto",
|
|
1208
1271
|
end: "ml-auto"
|
|
1209
1272
|
};
|
|
1210
|
-
|
|
1273
|
+
const minWidthClasses = {
|
|
1274
|
+
xs: "min-w-[20rem]",
|
|
1275
|
+
// 320px
|
|
1276
|
+
sm: "min-w-[24rem]",
|
|
1277
|
+
// 384px
|
|
1278
|
+
md: "min-w-[28rem]",
|
|
1279
|
+
// 448px
|
|
1280
|
+
lg: "min-w-[32rem]",
|
|
1281
|
+
// 512px
|
|
1282
|
+
xl: "min-w-[36rem]",
|
|
1283
|
+
// 576px
|
|
1284
|
+
"2xl": "min-w-[42rem]",
|
|
1285
|
+
// 672px
|
|
1286
|
+
"3xl": "min-w-[48rem]",
|
|
1287
|
+
// 768px
|
|
1288
|
+
full: "min-w-full"
|
|
1289
|
+
};
|
|
1290
|
+
const minHeightClasses = {
|
|
1291
|
+
xs: "min-h-[10rem]",
|
|
1292
|
+
// 160px
|
|
1293
|
+
sm: "min-h-[15rem]",
|
|
1294
|
+
// 240px
|
|
1295
|
+
md: "min-h-[20rem]",
|
|
1296
|
+
// 320px
|
|
1297
|
+
lg: "min-h-[25rem]",
|
|
1298
|
+
// 400px
|
|
1299
|
+
xl: "min-h-[30rem]",
|
|
1300
|
+
// 480px
|
|
1301
|
+
"2xl": "min-h-[35rem]",
|
|
1302
|
+
// 560px
|
|
1303
|
+
"3xl": "min-h-[40rem]",
|
|
1304
|
+
// 640px
|
|
1305
|
+
screen: "min-h-screen"
|
|
1306
|
+
};
|
|
1307
|
+
const minWidthClass = minWidth && minWidthClasses[minWidth] ? minWidthClasses[minWidth] : "";
|
|
1308
|
+
const minHeightClass = minHeight && minHeightClasses[minHeight] ? minHeightClasses[minHeight] : "";
|
|
1309
|
+
const inlineStyles = {
|
|
1310
|
+
...minWidth && !minWidthClasses[minWidth] && { minWidth },
|
|
1311
|
+
...minHeight && !minHeightClasses[minHeight] && { minHeight }
|
|
1312
|
+
};
|
|
1313
|
+
return /* @__PURE__ */ jsx(
|
|
1314
|
+
"div",
|
|
1315
|
+
{
|
|
1316
|
+
className: `px-4 ${sizeClasses[size]} ${paddingClasses[padding]} ${alignClasses[align]} ${minWidthClass} ${minHeightClass} ${className}`,
|
|
1317
|
+
style: Object.keys(inlineStyles).length > 0 ? inlineStyles : void 0,
|
|
1318
|
+
children
|
|
1319
|
+
}
|
|
1320
|
+
);
|
|
1211
1321
|
}
|
|
1212
1322
|
Container.displayName = "Container";
|
|
1213
1323
|
var container_default = Container;
|
|
@@ -1317,8 +1427,8 @@ var PageTransition = ({
|
|
|
1317
1427
|
type = "fade",
|
|
1318
1428
|
className = ""
|
|
1319
1429
|
}) => {
|
|
1320
|
-
const [isVisible, setIsVisible] =
|
|
1321
|
-
|
|
1430
|
+
const [isVisible, setIsVisible] = React5.useState(false);
|
|
1431
|
+
React5.useEffect(() => {
|
|
1322
1432
|
requestAnimationFrame(() => {
|
|
1323
1433
|
requestAnimationFrame(() => {
|
|
1324
1434
|
setIsVisible(true);
|
|
@@ -1440,20 +1550,34 @@ function Dropdown({
|
|
|
1440
1550
|
document.addEventListener("mousedown", handleClickOutside);
|
|
1441
1551
|
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
1442
1552
|
}, [isOpen, close]);
|
|
1443
|
-
|
|
1553
|
+
useLayoutEffect(() => {
|
|
1554
|
+
let raf;
|
|
1444
1555
|
if (isOpen) {
|
|
1445
1556
|
const itemEls = itemsRef.current.filter(Boolean);
|
|
1446
1557
|
if (itemEls.length) {
|
|
1447
|
-
|
|
1448
|
-
|
|
1558
|
+
raf = requestAnimationFrame(() => {
|
|
1559
|
+
setActiveIndex(0);
|
|
1560
|
+
itemEls[0]?.focus();
|
|
1561
|
+
});
|
|
1449
1562
|
}
|
|
1450
1563
|
} else {
|
|
1451
|
-
setActiveIndex(-1);
|
|
1564
|
+
raf = requestAnimationFrame(() => setActiveIndex(-1));
|
|
1452
1565
|
}
|
|
1566
|
+
return () => {
|
|
1567
|
+
if (raf) cancelAnimationFrame(raf);
|
|
1568
|
+
};
|
|
1453
1569
|
}, [isOpen]);
|
|
1454
|
-
const registerItem = (el, index) => {
|
|
1455
|
-
|
|
1456
|
-
|
|
1570
|
+
const registerItem = useCallback((el, index) => {
|
|
1571
|
+
if (typeof index === "number" && index >= 0) {
|
|
1572
|
+
itemsRef.current[index] = el;
|
|
1573
|
+
return;
|
|
1574
|
+
}
|
|
1575
|
+
if (el === null) {
|
|
1576
|
+
itemsRef.current = itemsRef.current.filter((x) => x !== el && x != null);
|
|
1577
|
+
return;
|
|
1578
|
+
}
|
|
1579
|
+
if (!itemsRef.current.includes(el)) itemsRef.current.push(el);
|
|
1580
|
+
}, []);
|
|
1457
1581
|
return /* @__PURE__ */ jsxs("div", { ref: dropdownRef, className: `relative ${className}`, children: [
|
|
1458
1582
|
/* @__PURE__ */ jsx(
|
|
1459
1583
|
"button",
|
|
@@ -1468,7 +1592,7 @@ function Dropdown({
|
|
|
1468
1592
|
children: trigger
|
|
1469
1593
|
}
|
|
1470
1594
|
),
|
|
1471
|
-
isOpen && /* @__PURE__ */ jsx(DropdownContext.Provider, { value: { requestClose: close, autoClose }, children: /* @__PURE__ */ jsx(
|
|
1595
|
+
isOpen && /* @__PURE__ */ jsx(DropdownContext.Provider, { value: { requestClose: close, autoClose, registerItem }, children: /* @__PURE__ */ jsx(
|
|
1472
1596
|
"div",
|
|
1473
1597
|
{
|
|
1474
1598
|
id: "dropdown-menu",
|
|
@@ -1477,10 +1601,7 @@ function Dropdown({
|
|
|
1477
1601
|
role: "menu",
|
|
1478
1602
|
"aria-orientation": "vertical",
|
|
1479
1603
|
tabIndex: -1,
|
|
1480
|
-
children
|
|
1481
|
-
if (!React3.isValidElement(child)) return child;
|
|
1482
|
-
return React3.cloneElement(child, { __dropdownIndex: i, __registerItem: registerItem, size });
|
|
1483
|
-
})
|
|
1604
|
+
children
|
|
1484
1605
|
}
|
|
1485
1606
|
) })
|
|
1486
1607
|
] });
|
|
@@ -1576,6 +1697,22 @@ Pagination.displayName = "Pagination";
|
|
|
1576
1697
|
var pagination_default = Pagination;
|
|
1577
1698
|
function Sidebar({ children, className = "", width = "16rem" }) {
|
|
1578
1699
|
const widthClass = width === "16rem" ? "w-64" : width === "4rem" ? "w-16" : "";
|
|
1700
|
+
const enhancedChildren = React5.Children.map(children, (child) => {
|
|
1701
|
+
if (!React5.isValidElement(child)) return child;
|
|
1702
|
+
const childProps = child.props || {};
|
|
1703
|
+
if ("href" in childProps) {
|
|
1704
|
+
const existing = typeof childProps.className === "string" ? childProps.className : "";
|
|
1705
|
+
const sidebarItemClasses = "flex items-center w-full justify-start gap-2 px-2 py-1.5 rounded hover:bg-muted";
|
|
1706
|
+
const childInner = child.props.children;
|
|
1707
|
+
const wrappedChildren = /* @__PURE__ */ jsx("span", { className: "flex items-center gap-2", children: childInner });
|
|
1708
|
+
const newProps = {
|
|
1709
|
+
...child.props,
|
|
1710
|
+
className: `${existing} ${sidebarItemClasses}`.trim()
|
|
1711
|
+
};
|
|
1712
|
+
return React5.cloneElement(child, newProps, wrappedChildren);
|
|
1713
|
+
}
|
|
1714
|
+
return child;
|
|
1715
|
+
});
|
|
1579
1716
|
return /* @__PURE__ */ jsx(
|
|
1580
1717
|
"nav",
|
|
1581
1718
|
{
|
|
@@ -1588,7 +1725,7 @@ function Sidebar({ children, className = "", width = "16rem" }) {
|
|
|
1588
1725
|
`.replace(/\s+/g, " "),
|
|
1589
1726
|
style: !widthClass ? { width } : void 0,
|
|
1590
1727
|
"aria-label": "Sidebar navigation",
|
|
1591
|
-
children: /* @__PURE__ */ jsx("div", { className: "flex-1 px-4 py-3
|
|
1728
|
+
children: /* @__PURE__ */ jsx("div", { className: "flex-1 px-4 py-3 flex flex-col gap-2", children: enhancedChildren })
|
|
1592
1729
|
}
|
|
1593
1730
|
);
|
|
1594
1731
|
}
|
|
@@ -1756,6 +1893,12 @@ function Toast({ message, children, type = "info", onClose, className = "", dura
|
|
|
1756
1893
|
warning: "bg-warning text-warning-foreground",
|
|
1757
1894
|
error: "bg-destructive text-destructive-foreground"
|
|
1758
1895
|
};
|
|
1896
|
+
const handleClose = useCallback(() => {
|
|
1897
|
+
setIsClosing(true);
|
|
1898
|
+
setTimeout(() => {
|
|
1899
|
+
onClose?.();
|
|
1900
|
+
}, 300);
|
|
1901
|
+
}, [onClose]);
|
|
1759
1902
|
useEffect(() => {
|
|
1760
1903
|
if (duration > 0) {
|
|
1761
1904
|
const timer = setTimeout(() => {
|
|
@@ -1764,25 +1907,20 @@ function Toast({ message, children, type = "info", onClose, className = "", dura
|
|
|
1764
1907
|
return () => clearTimeout(timer);
|
|
1765
1908
|
}
|
|
1766
1909
|
return void 0;
|
|
1767
|
-
}, [duration]);
|
|
1768
|
-
const
|
|
1769
|
-
setIsClosing(true);
|
|
1770
|
-
setTimeout(() => {
|
|
1771
|
-
onClose?.();
|
|
1772
|
-
}, 300);
|
|
1773
|
-
};
|
|
1774
|
-
return /* @__PURE__ */ jsxs(
|
|
1910
|
+
}, [duration, handleClose]);
|
|
1911
|
+
const toast = /* @__PURE__ */ jsxs(
|
|
1775
1912
|
"div",
|
|
1776
1913
|
{
|
|
1777
1914
|
role: "alert",
|
|
1778
1915
|
"aria-live": "polite",
|
|
1779
|
-
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}`,
|
|
1916
|
+
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}`,
|
|
1780
1917
|
children: [
|
|
1781
1918
|
/* @__PURE__ */ jsx("span", { children: children || message }),
|
|
1782
1919
|
onClose && /* @__PURE__ */ jsx("button", { onClick: handleClose, className: "ml-4 font-bold hover:opacity-70 transition-opacity", "aria-label": "Close", children: "\xD7" })
|
|
1783
1920
|
]
|
|
1784
1921
|
}
|
|
1785
1922
|
);
|
|
1923
|
+
return typeof document !== "undefined" ? createPortal(toast, document.body) : toast;
|
|
1786
1924
|
}
|
|
1787
1925
|
Toast.displayName = "Toast";
|
|
1788
1926
|
var toast_default = Toast;
|
|
@@ -1908,6 +2046,19 @@ function Tooltip({
|
|
|
1908
2046
|
}
|
|
1909
2047
|
Tooltip.displayName = "Tooltip";
|
|
1910
2048
|
var tooltip_default = Tooltip;
|
|
2049
|
+
|
|
2050
|
+
// src/utils/portal.ts
|
|
2051
|
+
function getPortalRoot(id = "hydn-ui-portal") {
|
|
2052
|
+
if (typeof document === "undefined") return null;
|
|
2053
|
+
let root = document.getElementById(id);
|
|
2054
|
+
if (!root) {
|
|
2055
|
+
root = document.createElement("div");
|
|
2056
|
+
root.id = id;
|
|
2057
|
+
document.body.appendChild(root);
|
|
2058
|
+
}
|
|
2059
|
+
return root;
|
|
2060
|
+
}
|
|
2061
|
+
var portal_default = getPortalRoot;
|
|
1911
2062
|
function useOverlay(options) {
|
|
1912
2063
|
const {
|
|
1913
2064
|
isOpen,
|
|
@@ -1923,9 +2074,10 @@ function useOverlay(options) {
|
|
|
1923
2074
|
const [shouldRender, setShouldRender] = useState(isOpen);
|
|
1924
2075
|
const [phase, setPhase] = useState("mount");
|
|
1925
2076
|
useLayoutEffect(() => {
|
|
1926
|
-
if (isOpen) {
|
|
2077
|
+
if (isOpen && !shouldRender) {
|
|
1927
2078
|
setShouldRender(true);
|
|
1928
2079
|
setPhase("mount");
|
|
2080
|
+
} else if (isOpen && shouldRender && phase === "mount") {
|
|
1929
2081
|
requestAnimationFrame(() => {
|
|
1930
2082
|
setPhase("animating-in");
|
|
1931
2083
|
let frame = 0;
|
|
@@ -1937,12 +2089,16 @@ function useOverlay(options) {
|
|
|
1937
2089
|
requestAnimationFrame(step);
|
|
1938
2090
|
}
|
|
1939
2091
|
};
|
|
1940
|
-
|
|
2092
|
+
if (animationFrames > 0) {
|
|
2093
|
+
requestAnimationFrame(step);
|
|
2094
|
+
} else {
|
|
2095
|
+
setPhase("visible");
|
|
2096
|
+
}
|
|
1941
2097
|
});
|
|
1942
|
-
} else if (!isOpen && shouldRender) {
|
|
2098
|
+
} else if (!isOpen && shouldRender && phase !== "animating-out") {
|
|
1943
2099
|
setPhase("animating-out");
|
|
1944
2100
|
}
|
|
1945
|
-
}, [isOpen, shouldRender, animationFrames]);
|
|
2101
|
+
}, [isOpen, shouldRender, phase, animationFrames]);
|
|
1946
2102
|
useEffect(() => {
|
|
1947
2103
|
if (phase === "animating-out" && unmountOnExit) {
|
|
1948
2104
|
const timeout = setTimeout(() => {
|
|
@@ -2027,7 +2183,8 @@ function Modal({
|
|
|
2027
2183
|
actions,
|
|
2028
2184
|
className = "",
|
|
2029
2185
|
ariaLabel,
|
|
2030
|
-
align = "center"
|
|
2186
|
+
align = "center",
|
|
2187
|
+
portalRoot = portal_default()
|
|
2031
2188
|
}) {
|
|
2032
2189
|
const {
|
|
2033
2190
|
phase,
|
|
@@ -2041,7 +2198,7 @@ function Modal({
|
|
|
2041
2198
|
animationFrames: 2,
|
|
2042
2199
|
restoreFocus: true
|
|
2043
2200
|
});
|
|
2044
|
-
|
|
2201
|
+
React5.useEffect(() => {
|
|
2045
2202
|
if (!isOpen) return;
|
|
2046
2203
|
const handleEscape = (e) => {
|
|
2047
2204
|
if (e.key === "Escape") {
|
|
@@ -2059,7 +2216,7 @@ function Modal({
|
|
|
2059
2216
|
const backdropOpacity = phase === "visible" || phase === "animating-in" ? "opacity-100" : "opacity-0 transition-opacity delay-50";
|
|
2060
2217
|
const hasStructured = title || description || content || actions;
|
|
2061
2218
|
const alignmentClasses = align === "center" ? "grid place-items-center" : "flex items-start justify-center pt-20";
|
|
2062
|
-
|
|
2219
|
+
const panel = /* @__PURE__ */ jsx(
|
|
2063
2220
|
"div",
|
|
2064
2221
|
{
|
|
2065
2222
|
"data-phase": phase,
|
|
@@ -2093,6 +2250,7 @@ function Modal({
|
|
|
2093
2250
|
)
|
|
2094
2251
|
}
|
|
2095
2252
|
);
|
|
2253
|
+
return portalRoot ? createPortal(panel, portalRoot) : panel;
|
|
2096
2254
|
}
|
|
2097
2255
|
Modal.displayName = "Modal";
|
|
2098
2256
|
var modal_default = Modal;
|
|
@@ -2209,12 +2367,13 @@ function Popover({ trigger, children, content, position = "bottom", className =
|
|
|
2209
2367
|
}
|
|
2210
2368
|
Popover.displayName = "Popover";
|
|
2211
2369
|
var popover_default = Popover;
|
|
2212
|
-
function Alert({ children, type = "info", dismissible = false, onClose, className = "" }) {
|
|
2370
|
+
function Alert({ children, type = "info", dismissible = false, onClose, className = "", position = "relative", duration = 0 }) {
|
|
2371
|
+
const [isClosing, setIsClosing] = useState(false);
|
|
2213
2372
|
const typeClasses = {
|
|
2214
|
-
info: "bg-info/
|
|
2215
|
-
success: "bg-success/
|
|
2216
|
-
warning: "bg-warning/
|
|
2217
|
-
error: "bg-destructive/
|
|
2373
|
+
info: "bg-info/20 text-foreground border-info/50 backdrop-blur-sm",
|
|
2374
|
+
success: "bg-success/20 text-foreground border-success/50 backdrop-blur-sm",
|
|
2375
|
+
warning: "bg-warning/20 text-foreground border-warning/50 backdrop-blur-sm",
|
|
2376
|
+
error: "bg-destructive/20 text-foreground border-destructive/50 backdrop-blur-sm"
|
|
2218
2377
|
};
|
|
2219
2378
|
const iconClasses = {
|
|
2220
2379
|
info: "text-info",
|
|
@@ -2222,6 +2381,21 @@ function Alert({ children, type = "info", dismissible = false, onClose, classNam
|
|
|
2222
2381
|
warning: "text-warning",
|
|
2223
2382
|
error: "text-destructive"
|
|
2224
2383
|
};
|
|
2384
|
+
const handleClose = useCallback(() => {
|
|
2385
|
+
setIsClosing(true);
|
|
2386
|
+
setTimeout(() => {
|
|
2387
|
+
onClose?.();
|
|
2388
|
+
}, 300);
|
|
2389
|
+
}, [onClose]);
|
|
2390
|
+
useEffect(() => {
|
|
2391
|
+
if (duration > 0 && onClose) {
|
|
2392
|
+
const timer = setTimeout(() => {
|
|
2393
|
+
handleClose();
|
|
2394
|
+
}, duration);
|
|
2395
|
+
return () => clearTimeout(timer);
|
|
2396
|
+
}
|
|
2397
|
+
return void 0;
|
|
2398
|
+
}, [duration, onClose, handleClose]);
|
|
2225
2399
|
const icons = {
|
|
2226
2400
|
info: /* @__PURE__ */ jsx("svg", { className: "w-5 h-5 flex-shrink-0", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx(
|
|
2227
2401
|
"path",
|
|
@@ -2256,19 +2430,44 @@ function Alert({ children, type = "info", dismissible = false, onClose, classNam
|
|
|
2256
2430
|
}
|
|
2257
2431
|
) })
|
|
2258
2432
|
};
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2433
|
+
const positionClasses = {
|
|
2434
|
+
top: "fixed top-4 left-1/2 -translate-x-1/2 z-[9999] max-w-2xl w-full mx-4",
|
|
2435
|
+
bottom: "fixed bottom-4 left-1/2 -translate-x-1/2 z-[9999] max-w-2xl w-full mx-4",
|
|
2436
|
+
relative: ""
|
|
2437
|
+
};
|
|
2438
|
+
const getAnimationClasses = () => {
|
|
2439
|
+
if (position === "top") {
|
|
2440
|
+
return isClosing ? "opacity-0 -translate-y-full" : "opacity-100 translate-y-0 animate-slideInTop";
|
|
2441
|
+
}
|
|
2442
|
+
if (position === "bottom") {
|
|
2443
|
+
return isClosing ? "opacity-0 translate-y-full" : "opacity-100 translate-y-0 animate-slideInBottom";
|
|
2444
|
+
}
|
|
2445
|
+
return isClosing ? "opacity-0" : "opacity-100";
|
|
2446
|
+
};
|
|
2447
|
+
const alertContent = /* @__PURE__ */ jsxs(
|
|
2448
|
+
"div",
|
|
2449
|
+
{
|
|
2450
|
+
role: "alert",
|
|
2451
|
+
className: `p-4 border rounded-lg flex items-start gap-3 transition-all duration-300 ease-out ${typeClasses[type]} ${positionClasses[position]} ${getAnimationClasses()} ${className}`,
|
|
2452
|
+
children: [
|
|
2453
|
+
/* @__PURE__ */ jsx("span", { className: iconClasses[type], children: icons[type] }),
|
|
2454
|
+
/* @__PURE__ */ jsx("span", { className: "flex-1 text-sm", children }),
|
|
2455
|
+
dismissible && onClose && /* @__PURE__ */ jsx(
|
|
2456
|
+
"button",
|
|
2457
|
+
{
|
|
2458
|
+
onClick: handleClose,
|
|
2459
|
+
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",
|
|
2460
|
+
"aria-label": "Close alert",
|
|
2461
|
+
children: /* @__PURE__ */ jsx("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
|
|
2462
|
+
}
|
|
2463
|
+
)
|
|
2464
|
+
]
|
|
2465
|
+
}
|
|
2466
|
+
);
|
|
2467
|
+
if (position !== "relative" && typeof document !== "undefined") {
|
|
2468
|
+
return createPortal(alertContent, document.body);
|
|
2469
|
+
}
|
|
2470
|
+
return alertContent;
|
|
2272
2471
|
}
|
|
2273
2472
|
Alert.displayName = "Alert";
|
|
2274
2473
|
var alert_default = Alert;
|
|
@@ -3385,7 +3584,7 @@ function Drawer({
|
|
|
3385
3584
|
closeOnEscape = true,
|
|
3386
3585
|
closeOnOutside = true,
|
|
3387
3586
|
unmountOnExit = true,
|
|
3388
|
-
portalRoot =
|
|
3587
|
+
portalRoot = portal_default(),
|
|
3389
3588
|
noAnimation = false
|
|
3390
3589
|
}) {
|
|
3391
3590
|
const { phase, shouldRender, ref, getPhaseClass } = useOverlay_default({
|
|
@@ -3394,8 +3593,8 @@ function Drawer({
|
|
|
3394
3593
|
restoreFocus: true,
|
|
3395
3594
|
focusTrap: true,
|
|
3396
3595
|
unmountOnExit,
|
|
3397
|
-
exitDuration: noAnimation ? 0 :
|
|
3398
|
-
animationFrames: noAnimation ? 0 :
|
|
3596
|
+
exitDuration: noAnimation ? 0 : 250,
|
|
3597
|
+
animationFrames: noAnimation ? 0 : 0
|
|
3399
3598
|
});
|
|
3400
3599
|
if (!shouldRender) return null;
|
|
3401
3600
|
const sizeClasses = {
|
|
@@ -3419,7 +3618,7 @@ function Drawer({
|
|
|
3419
3618
|
};
|
|
3420
3619
|
const openTransform = "translate-x-0 translate-y-0";
|
|
3421
3620
|
const panelTransform = noAnimation ? "" : getPhaseClass(openTransform, closedTransform[position]);
|
|
3422
|
-
const overlayOpacity = noAnimation ? "" : getPhaseClass("opacity-100", "opacity-0");
|
|
3621
|
+
const overlayOpacity = noAnimation ? "opacity-100" : getPhaseClass("opacity-100", "opacity-0");
|
|
3423
3622
|
const handleKeyDown = (e) => {
|
|
3424
3623
|
if (e.key === "Escape" && closeOnEscape) {
|
|
3425
3624
|
e.stopPropagation();
|
|
@@ -3428,11 +3627,21 @@ function Drawer({
|
|
|
3428
3627
|
};
|
|
3429
3628
|
const panel = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3430
3629
|
/* @__PURE__ */ jsx(
|
|
3431
|
-
"
|
|
3630
|
+
"button",
|
|
3432
3631
|
{
|
|
3433
|
-
|
|
3434
|
-
|
|
3632
|
+
type: "button",
|
|
3633
|
+
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`,
|
|
3634
|
+
"aria-label": closeOnOutside ? "Close overlay" : void 0,
|
|
3635
|
+
"aria-hidden": !closeOnOutside,
|
|
3636
|
+
tabIndex: closeOnOutside ? 0 : -1,
|
|
3435
3637
|
onClick: () => closeOnOutside && onClose(),
|
|
3638
|
+
onKeyDown: (e) => {
|
|
3639
|
+
if (!closeOnOutside) return;
|
|
3640
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
3641
|
+
e.preventDefault();
|
|
3642
|
+
onClose();
|
|
3643
|
+
}
|
|
3644
|
+
},
|
|
3436
3645
|
"data-phase": phase
|
|
3437
3646
|
}
|
|
3438
3647
|
),
|
|
@@ -3446,7 +3655,7 @@ function Drawer({
|
|
|
3446
3655
|
tabIndex: -1,
|
|
3447
3656
|
"data-phase": phase,
|
|
3448
3657
|
"data-position": position,
|
|
3449
|
-
className: `fixed ${edgeClasses[position]} ${position === "left" || position === "right" ? sizeClasses[size] : ""} bg-card text-card-foreground shadow-2xl z-
|
|
3658
|
+
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}`,
|
|
3450
3659
|
onKeyDown: handleKeyDown,
|
|
3451
3660
|
children: [
|
|
3452
3661
|
title && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-5 py-4 border-b border-border/60 bg-card/95 backdrop-blur-sm", children: [
|
|
@@ -3726,10 +3935,14 @@ function useScrollReset(deps, container) {
|
|
|
3726
3935
|
let cancelled = false;
|
|
3727
3936
|
const maxRaf = 6;
|
|
3728
3937
|
let rafCount = 0;
|
|
3938
|
+
const isRef = (obj) => {
|
|
3939
|
+
return typeof obj === "object" && obj !== null && "current" in obj;
|
|
3940
|
+
};
|
|
3729
3941
|
const setAllScrollTop = () => {
|
|
3730
3942
|
if (cancelled) return;
|
|
3731
3943
|
window.scrollTo(0, 0);
|
|
3732
|
-
|
|
3944
|
+
const resolved = isRef(container) ? container.current : container;
|
|
3945
|
+
if (resolved) resolved.scrollTop = 0;
|
|
3733
3946
|
document.documentElement.scrollTop = 0;
|
|
3734
3947
|
document.body.scrollTop = 0;
|
|
3735
3948
|
};
|
|
@@ -3796,7 +4009,7 @@ function LeftNavLayout({
|
|
|
3796
4009
|
navRef.current.scrollTop = scrollPosRef.current;
|
|
3797
4010
|
}
|
|
3798
4011
|
}, [children]);
|
|
3799
|
-
useScrollReset_default([children], contentRef
|
|
4012
|
+
useScrollReset_default([children], contentRef);
|
|
3800
4013
|
const containerClasses = embedded ? "flex bg-background border border-border rounded-lg overflow-hidden" : "flex h-[calc(100vh-4rem)] bg-background";
|
|
3801
4014
|
return /* @__PURE__ */ jsxs("div", { className: `${containerClasses} ${className}`, children: [
|
|
3802
4015
|
mobileCollapsible && mobileMenuOpen && /* @__PURE__ */ jsx(
|
|
@@ -3828,17 +4041,34 @@ function LeftNavLayout({
|
|
|
3828
4041
|
"div",
|
|
3829
4042
|
{
|
|
3830
4043
|
className: `
|
|
3831
|
-
flex items-center h-12 flex-shrink-0
|
|
4044
|
+
relative flex items-center h-12 flex-shrink-0
|
|
3832
4045
|
px-4 border-b border-border
|
|
3833
|
-
${collapsed ? "justify-center" : "justify-between"}
|
|
3834
4046
|
`,
|
|
3835
4047
|
children: [
|
|
3836
|
-
|
|
4048
|
+
/* @__PURE__ */ jsx(
|
|
4049
|
+
"span",
|
|
4050
|
+
{
|
|
4051
|
+
className: `
|
|
4052
|
+
text-sm font-semibold text-foreground
|
|
4053
|
+
transition-all duration-300 ease-in-out
|
|
4054
|
+
${collapsed ? "opacity-0 w-0 overflow-hidden" : "opacity-100"}
|
|
4055
|
+
`,
|
|
4056
|
+
children: "Navigation"
|
|
4057
|
+
}
|
|
4058
|
+
),
|
|
3837
4059
|
/* @__PURE__ */ jsx(
|
|
3838
4060
|
"button",
|
|
3839
4061
|
{
|
|
3840
4062
|
onClick: toggleCollapsed,
|
|
3841
|
-
className:
|
|
4063
|
+
className: `
|
|
4064
|
+
hidden lg:flex items-center justify-center
|
|
4065
|
+
w-8 h-8 rounded-md
|
|
4066
|
+
text-muted-foreground hover:text-foreground
|
|
4067
|
+
hover:bg-muted
|
|
4068
|
+
transition-all duration-300 ease-in-out
|
|
4069
|
+
focus:outline-none focus:ring-2 focus:ring-ring
|
|
4070
|
+
${collapsed ? "absolute left-1/2 -translate-x-1/2" : "absolute right-4"}
|
|
4071
|
+
`,
|
|
3842
4072
|
"aria-label": collapsed ? "Expand sidebar" : "Collapse sidebar",
|
|
3843
4073
|
type: "button",
|
|
3844
4074
|
children: collapsed ? /* @__PURE__ */ jsx(IconChevronRight, { size: 20 }) : /* @__PURE__ */ jsx(IconChevronLeft, { size: 20 })
|