@hyddenlabs/hydn-ui 0.3.0-alpha.1 → 0.3.0-fix-animation-drawer.1

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.d.cts CHANGED
@@ -264,8 +264,11 @@ type NavProps = {
264
264
  children: React__default.ReactNode;
265
265
  className?: string;
266
266
  ariaLabel?: string;
267
+ direction?: 'horizontal' | 'vertical';
268
+ spacing?: 'none' | 'sm' | 'md' | 'lg' | 'xl';
269
+ align?: 'start' | 'center' | 'end' | 'stretch';
267
270
  };
268
- declare function Nav({ children, className, ariaLabel }: Readonly<NavProps>): react_jsx_runtime.JSX.Element;
271
+ declare function Nav({ children, className, ariaLabel, direction, spacing, align }: Readonly<NavProps>): react_jsx_runtime.JSX.Element;
269
272
  declare namespace Nav {
270
273
  var displayName: string;
271
274
  }
@@ -433,8 +436,9 @@ type ModalProps = {
433
436
  className?: string;
434
437
  ariaLabel?: string;
435
438
  align?: 'center' | 'top';
439
+ portalRoot?: HTMLElement | null;
436
440
  };
437
- declare function Modal({ isOpen, onClose, children, title, description, content, actions, className, ariaLabel, align }: Readonly<ModalProps>): react_jsx_runtime.JSX.Element | null;
441
+ declare function Modal({ isOpen, onClose, children, title, description, content, actions, className, ariaLabel, align, portalRoot }: Readonly<ModalProps>): react_jsx_runtime.JSX.Element | null;
438
442
  declare namespace Modal {
439
443
  var displayName: string;
440
444
  }
@@ -487,8 +491,10 @@ type AlertProps = {
487
491
  dismissible?: boolean;
488
492
  onClose?: () => void;
489
493
  className?: string;
494
+ position?: 'top' | 'bottom' | 'relative';
495
+ duration?: number;
490
496
  };
491
- declare function Alert({ children, type, dismissible, onClose, className }: Readonly<AlertProps>): react_jsx_runtime.JSX.Element;
497
+ declare function Alert({ children, type, dismissible, onClose, className, position, duration }: Readonly<AlertProps>): react_jsx_runtime.JSX.Element;
492
498
  declare namespace Alert {
493
499
  var displayName: string;
494
500
  }
@@ -883,8 +889,10 @@ type ContainerProps = {
883
889
  size?: 'sm' | 'md' | 'lg' | 'xl' | 'full';
884
890
  padding?: 'none' | 'sm' | 'md' | 'lg' | 'xl';
885
891
  align?: 'start' | 'center' | 'end';
892
+ minWidth?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full' | string;
893
+ minHeight?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'screen' | string;
886
894
  };
887
- declare function Container({ children, className, size, padding, align }: Readonly<ContainerProps>): react_jsx_runtime.JSX.Element;
895
+ declare function Container({ children, className, size, padding, align, minWidth, minHeight }: Readonly<ContainerProps>): react_jsx_runtime.JSX.Element;
888
896
  declare namespace Container {
889
897
  var displayName: string;
890
898
  }
package/dist/index.d.ts CHANGED
@@ -264,8 +264,11 @@ type NavProps = {
264
264
  children: React__default.ReactNode;
265
265
  className?: string;
266
266
  ariaLabel?: string;
267
+ direction?: 'horizontal' | 'vertical';
268
+ spacing?: 'none' | 'sm' | 'md' | 'lg' | 'xl';
269
+ align?: 'start' | 'center' | 'end' | 'stretch';
267
270
  };
268
- declare function Nav({ children, className, ariaLabel }: Readonly<NavProps>): react_jsx_runtime.JSX.Element;
271
+ declare function Nav({ children, className, ariaLabel, direction, spacing, align }: Readonly<NavProps>): react_jsx_runtime.JSX.Element;
269
272
  declare namespace Nav {
270
273
  var displayName: string;
271
274
  }
@@ -433,8 +436,9 @@ type ModalProps = {
433
436
  className?: string;
434
437
  ariaLabel?: string;
435
438
  align?: 'center' | 'top';
439
+ portalRoot?: HTMLElement | null;
436
440
  };
437
- declare function Modal({ isOpen, onClose, children, title, description, content, actions, className, ariaLabel, align }: Readonly<ModalProps>): react_jsx_runtime.JSX.Element | null;
441
+ declare function Modal({ isOpen, onClose, children, title, description, content, actions, className, ariaLabel, align, portalRoot }: Readonly<ModalProps>): react_jsx_runtime.JSX.Element | null;
438
442
  declare namespace Modal {
439
443
  var displayName: string;
440
444
  }
@@ -487,8 +491,10 @@ type AlertProps = {
487
491
  dismissible?: boolean;
488
492
  onClose?: () => void;
489
493
  className?: string;
494
+ position?: 'top' | 'bottom' | 'relative';
495
+ duration?: number;
490
496
  };
491
- declare function Alert({ children, type, dismissible, onClose, className }: Readonly<AlertProps>): react_jsx_runtime.JSX.Element;
497
+ declare function Alert({ children, type, dismissible, onClose, className, position, duration }: Readonly<AlertProps>): react_jsx_runtime.JSX.Element;
492
498
  declare namespace Alert {
493
499
  var displayName: string;
494
500
  }
@@ -883,8 +889,10 @@ type ContainerProps = {
883
889
  size?: 'sm' | 'md' | 'lg' | 'xl' | 'full';
884
890
  padding?: 'none' | 'sm' | 'md' | 'lg' | 'xl';
885
891
  align?: 'start' | 'center' | 'end';
892
+ minWidth?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full' | string;
893
+ minHeight?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'screen' | string;
886
894
  };
887
- declare function Container({ children, className, size, padding, align }: Readonly<ContainerProps>): react_jsx_runtime.JSX.Element;
895
+ declare function Container({ children, className, size, padding, align, minWidth, minHeight }: Readonly<ContainerProps>): react_jsx_runtime.JSX.Element;
888
896
  declare namespace Container {
889
897
  var displayName: string;
890
898
  }
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
- import React3, { createContext, useState, useRef, useEffect, isValidElement, cloneElement, useCallback, useMemo, createElement, useContext, useLayoutEffect } from 'react';
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 inputId = id || `radio-${value || Math.random().toString(36).slice(2)}`;
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,
@@ -1176,8 +1177,31 @@ function DatePicker({
1176
1177
  }
1177
1178
  DatePicker.displayName = "DatePicker";
1178
1179
  var date_picker_default = DatePicker;
1179
- function Nav({ children, className = "", ariaLabel = "Main navigation" }) {
1180
- return /* @__PURE__ */ jsx("nav", { "aria-label": ariaLabel, className: `flex items-center ${className}`, children });
1180
+ function Nav({
1181
+ children,
1182
+ className = "",
1183
+ ariaLabel = "Main navigation",
1184
+ direction = "horizontal",
1185
+ spacing = "md",
1186
+ align = "center"
1187
+ }) {
1188
+ const spacingClasses = {
1189
+ none: "gap-0",
1190
+ sm: "gap-2",
1191
+ md: "gap-4",
1192
+ lg: "gap-6",
1193
+ xl: "gap-8"
1194
+ };
1195
+ const alignClasses = {
1196
+ start: "items-start",
1197
+ center: "items-center",
1198
+ end: "items-end",
1199
+ stretch: "items-stretch"
1200
+ };
1201
+ const directionClass = direction === "horizontal" ? "flex-row" : "flex-col";
1202
+ const spacingClass = spacingClasses[spacing];
1203
+ const alignClass = alignClasses[align];
1204
+ return /* @__PURE__ */ jsx("nav", { "aria-label": ariaLabel, className: `flex ${directionClass} ${spacingClass} ${alignClass} ${className}`, children });
1181
1205
  }
1182
1206
  Nav.displayName = "Nav";
1183
1207
  var nav_default = Nav;
@@ -1186,7 +1210,9 @@ function Container({
1186
1210
  className = "",
1187
1211
  size = "lg",
1188
1212
  padding = "lg",
1189
- align = "center"
1213
+ align = "center",
1214
+ minWidth,
1215
+ minHeight
1190
1216
  }) {
1191
1217
  const sizeClasses = {
1192
1218
  sm: "max-w-screen-sm",
@@ -1207,7 +1233,54 @@ function Container({
1207
1233
  center: "mx-auto",
1208
1234
  end: "ml-auto"
1209
1235
  };
1210
- return /* @__PURE__ */ jsx("div", { className: `px-4 ${sizeClasses[size]} ${paddingClasses[padding]} ${alignClasses[align]} ${className}`, children });
1236
+ const minWidthClasses = {
1237
+ xs: "min-w-[20rem]",
1238
+ // 320px
1239
+ sm: "min-w-[24rem]",
1240
+ // 384px
1241
+ md: "min-w-[28rem]",
1242
+ // 448px
1243
+ lg: "min-w-[32rem]",
1244
+ // 512px
1245
+ xl: "min-w-[36rem]",
1246
+ // 576px
1247
+ "2xl": "min-w-[42rem]",
1248
+ // 672px
1249
+ "3xl": "min-w-[48rem]",
1250
+ // 768px
1251
+ full: "min-w-full"
1252
+ };
1253
+ const minHeightClasses = {
1254
+ xs: "min-h-[10rem]",
1255
+ // 160px
1256
+ sm: "min-h-[15rem]",
1257
+ // 240px
1258
+ md: "min-h-[20rem]",
1259
+ // 320px
1260
+ lg: "min-h-[25rem]",
1261
+ // 400px
1262
+ xl: "min-h-[30rem]",
1263
+ // 480px
1264
+ "2xl": "min-h-[35rem]",
1265
+ // 560px
1266
+ "3xl": "min-h-[40rem]",
1267
+ // 640px
1268
+ screen: "min-h-screen"
1269
+ };
1270
+ const minWidthClass = minWidth && minWidthClasses[minWidth] ? minWidthClasses[minWidth] : "";
1271
+ const minHeightClass = minHeight && minHeightClasses[minHeight] ? minHeightClasses[minHeight] : "";
1272
+ const inlineStyles = {
1273
+ ...minWidth && !minWidthClasses[minWidth] && { minWidth },
1274
+ ...minHeight && !minHeightClasses[minHeight] && { minHeight }
1275
+ };
1276
+ return /* @__PURE__ */ jsx(
1277
+ "div",
1278
+ {
1279
+ className: `px-4 ${sizeClasses[size]} ${paddingClasses[padding]} ${alignClasses[align]} ${minWidthClass} ${minHeightClass} ${className}`,
1280
+ style: Object.keys(inlineStyles).length > 0 ? inlineStyles : void 0,
1281
+ children
1282
+ }
1283
+ );
1211
1284
  }
1212
1285
  Container.displayName = "Container";
1213
1286
  var container_default = Container;
@@ -1317,8 +1390,8 @@ var PageTransition = ({
1317
1390
  type = "fade",
1318
1391
  className = ""
1319
1392
  }) => {
1320
- const [isVisible, setIsVisible] = React3.useState(false);
1321
- React3.useEffect(() => {
1393
+ const [isVisible, setIsVisible] = React5.useState(false);
1394
+ React5.useEffect(() => {
1322
1395
  requestAnimationFrame(() => {
1323
1396
  requestAnimationFrame(() => {
1324
1397
  setIsVisible(true);
@@ -1440,20 +1513,34 @@ function Dropdown({
1440
1513
  document.addEventListener("mousedown", handleClickOutside);
1441
1514
  return () => document.removeEventListener("mousedown", handleClickOutside);
1442
1515
  }, [isOpen, close]);
1443
- useEffect(() => {
1516
+ useLayoutEffect(() => {
1517
+ let raf;
1444
1518
  if (isOpen) {
1445
1519
  const itemEls = itemsRef.current.filter(Boolean);
1446
1520
  if (itemEls.length) {
1447
- setActiveIndex(0);
1448
- itemEls[0]?.focus();
1521
+ raf = requestAnimationFrame(() => {
1522
+ setActiveIndex(0);
1523
+ itemEls[0]?.focus();
1524
+ });
1449
1525
  }
1450
1526
  } else {
1451
- setActiveIndex(-1);
1527
+ raf = requestAnimationFrame(() => setActiveIndex(-1));
1452
1528
  }
1529
+ return () => {
1530
+ if (raf) cancelAnimationFrame(raf);
1531
+ };
1453
1532
  }, [isOpen]);
1454
- const registerItem = (el, index) => {
1455
- itemsRef.current[index] = el;
1456
- };
1533
+ const registerItem = useCallback((el, index) => {
1534
+ if (typeof index === "number" && index >= 0) {
1535
+ itemsRef.current[index] = el;
1536
+ return;
1537
+ }
1538
+ if (el === null) {
1539
+ itemsRef.current = itemsRef.current.filter((x) => x !== el && x != null);
1540
+ return;
1541
+ }
1542
+ if (!itemsRef.current.includes(el)) itemsRef.current.push(el);
1543
+ }, []);
1457
1544
  return /* @__PURE__ */ jsxs("div", { ref: dropdownRef, className: `relative ${className}`, children: [
1458
1545
  /* @__PURE__ */ jsx(
1459
1546
  "button",
@@ -1468,7 +1555,7 @@ function Dropdown({
1468
1555
  children: trigger
1469
1556
  }
1470
1557
  ),
1471
- isOpen && /* @__PURE__ */ jsx(DropdownContext.Provider, { value: { requestClose: close, autoClose }, children: /* @__PURE__ */ jsx(
1558
+ isOpen && /* @__PURE__ */ jsx(DropdownContext.Provider, { value: { requestClose: close, autoClose, registerItem }, children: /* @__PURE__ */ jsx(
1472
1559
  "div",
1473
1560
  {
1474
1561
  id: "dropdown-menu",
@@ -1477,10 +1564,7 @@ function Dropdown({
1477
1564
  role: "menu",
1478
1565
  "aria-orientation": "vertical",
1479
1566
  tabIndex: -1,
1480
- children: React3.Children.map(children, (child, i) => {
1481
- if (!React3.isValidElement(child)) return child;
1482
- return React3.cloneElement(child, { __dropdownIndex: i, __registerItem: registerItem, size });
1483
- })
1567
+ children
1484
1568
  }
1485
1569
  ) })
1486
1570
  ] });
@@ -1576,6 +1660,22 @@ Pagination.displayName = "Pagination";
1576
1660
  var pagination_default = Pagination;
1577
1661
  function Sidebar({ children, className = "", width = "16rem" }) {
1578
1662
  const widthClass = width === "16rem" ? "w-64" : width === "4rem" ? "w-16" : "";
1663
+ const enhancedChildren = React5.Children.map(children, (child) => {
1664
+ if (!React5.isValidElement(child)) return child;
1665
+ const childProps = child.props || {};
1666
+ if ("href" in childProps) {
1667
+ const existing = typeof childProps.className === "string" ? childProps.className : "";
1668
+ const sidebarItemClasses = "flex items-center w-full justify-start gap-2 px-2 py-1.5 rounded hover:bg-muted";
1669
+ const childInner = child.props.children;
1670
+ const wrappedChildren = /* @__PURE__ */ jsx("span", { className: "flex items-center gap-2", children: childInner });
1671
+ const newProps = {
1672
+ ...child.props,
1673
+ className: `${existing} ${sidebarItemClasses}`.trim()
1674
+ };
1675
+ return React5.cloneElement(child, newProps, wrappedChildren);
1676
+ }
1677
+ return child;
1678
+ });
1579
1679
  return /* @__PURE__ */ jsx(
1580
1680
  "nav",
1581
1681
  {
@@ -1588,7 +1688,7 @@ function Sidebar({ children, className = "", width = "16rem" }) {
1588
1688
  `.replace(/\s+/g, " "),
1589
1689
  style: !widthClass ? { width } : void 0,
1590
1690
  "aria-label": "Sidebar navigation",
1591
- children: /* @__PURE__ */ jsx("div", { className: "flex-1 px-4 py-3 space-y-2", children })
1691
+ children: /* @__PURE__ */ jsx("div", { className: "flex-1 px-4 py-3 flex flex-col gap-2", children: enhancedChildren })
1592
1692
  }
1593
1693
  );
1594
1694
  }
@@ -1756,6 +1856,12 @@ function Toast({ message, children, type = "info", onClose, className = "", dura
1756
1856
  warning: "bg-warning text-warning-foreground",
1757
1857
  error: "bg-destructive text-destructive-foreground"
1758
1858
  };
1859
+ const handleClose = useCallback(() => {
1860
+ setIsClosing(true);
1861
+ setTimeout(() => {
1862
+ onClose?.();
1863
+ }, 300);
1864
+ }, [onClose]);
1759
1865
  useEffect(() => {
1760
1866
  if (duration > 0) {
1761
1867
  const timer = setTimeout(() => {
@@ -1764,25 +1870,20 @@ function Toast({ message, children, type = "info", onClose, className = "", dura
1764
1870
  return () => clearTimeout(timer);
1765
1871
  }
1766
1872
  return void 0;
1767
- }, [duration]);
1768
- const handleClose = () => {
1769
- setIsClosing(true);
1770
- setTimeout(() => {
1771
- onClose?.();
1772
- }, 300);
1773
- };
1774
- return /* @__PURE__ */ jsxs(
1873
+ }, [duration, handleClose]);
1874
+ const toast = /* @__PURE__ */ jsxs(
1775
1875
  "div",
1776
1876
  {
1777
1877
  role: "alert",
1778
1878
  "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}`,
1879
+ 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
1880
  children: [
1781
1881
  /* @__PURE__ */ jsx("span", { children: children || message }),
1782
1882
  onClose && /* @__PURE__ */ jsx("button", { onClick: handleClose, className: "ml-4 font-bold hover:opacity-70 transition-opacity", "aria-label": "Close", children: "\xD7" })
1783
1883
  ]
1784
1884
  }
1785
1885
  );
1886
+ return typeof document !== "undefined" ? createPortal(toast, document.body) : toast;
1786
1887
  }
1787
1888
  Toast.displayName = "Toast";
1788
1889
  var toast_default = Toast;
@@ -1908,6 +2009,19 @@ function Tooltip({
1908
2009
  }
1909
2010
  Tooltip.displayName = "Tooltip";
1910
2011
  var tooltip_default = Tooltip;
2012
+
2013
+ // src/utils/portal.ts
2014
+ function getPortalRoot(id = "hydn-ui-portal") {
2015
+ if (typeof document === "undefined") return null;
2016
+ let root = document.getElementById(id);
2017
+ if (!root) {
2018
+ root = document.createElement("div");
2019
+ root.id = id;
2020
+ document.body.appendChild(root);
2021
+ }
2022
+ return root;
2023
+ }
2024
+ var portal_default = getPortalRoot;
1911
2025
  function useOverlay(options) {
1912
2026
  const {
1913
2027
  isOpen,
@@ -1923,9 +2037,10 @@ function useOverlay(options) {
1923
2037
  const [shouldRender, setShouldRender] = useState(isOpen);
1924
2038
  const [phase, setPhase] = useState("mount");
1925
2039
  useLayoutEffect(() => {
1926
- if (isOpen) {
2040
+ if (isOpen && !shouldRender) {
1927
2041
  setShouldRender(true);
1928
2042
  setPhase("mount");
2043
+ } else if (isOpen && shouldRender && phase === "mount") {
1929
2044
  requestAnimationFrame(() => {
1930
2045
  setPhase("animating-in");
1931
2046
  let frame = 0;
@@ -1937,12 +2052,16 @@ function useOverlay(options) {
1937
2052
  requestAnimationFrame(step);
1938
2053
  }
1939
2054
  };
1940
- requestAnimationFrame(step);
2055
+ if (animationFrames > 0) {
2056
+ requestAnimationFrame(step);
2057
+ } else {
2058
+ setPhase("visible");
2059
+ }
1941
2060
  });
1942
- } else if (!isOpen && shouldRender) {
2061
+ } else if (!isOpen && shouldRender && phase !== "animating-out") {
1943
2062
  setPhase("animating-out");
1944
2063
  }
1945
- }, [isOpen, shouldRender, animationFrames]);
2064
+ }, [isOpen, shouldRender, phase, animationFrames]);
1946
2065
  useEffect(() => {
1947
2066
  if (phase === "animating-out" && unmountOnExit) {
1948
2067
  const timeout = setTimeout(() => {
@@ -2027,7 +2146,8 @@ function Modal({
2027
2146
  actions,
2028
2147
  className = "",
2029
2148
  ariaLabel,
2030
- align = "center"
2149
+ align = "center",
2150
+ portalRoot = portal_default()
2031
2151
  }) {
2032
2152
  const {
2033
2153
  phase,
@@ -2041,7 +2161,7 @@ function Modal({
2041
2161
  animationFrames: 2,
2042
2162
  restoreFocus: true
2043
2163
  });
2044
- React3.useEffect(() => {
2164
+ React5.useEffect(() => {
2045
2165
  if (!isOpen) return;
2046
2166
  const handleEscape = (e) => {
2047
2167
  if (e.key === "Escape") {
@@ -2059,7 +2179,7 @@ function Modal({
2059
2179
  const backdropOpacity = phase === "visible" || phase === "animating-in" ? "opacity-100" : "opacity-0 transition-opacity delay-50";
2060
2180
  const hasStructured = title || description || content || actions;
2061
2181
  const alignmentClasses = align === "center" ? "grid place-items-center" : "flex items-start justify-center pt-20";
2062
- return /* @__PURE__ */ jsx(
2182
+ const panel = /* @__PURE__ */ jsx(
2063
2183
  "div",
2064
2184
  {
2065
2185
  "data-phase": phase,
@@ -2093,6 +2213,7 @@ function Modal({
2093
2213
  )
2094
2214
  }
2095
2215
  );
2216
+ return portalRoot ? createPortal(panel, portalRoot) : panel;
2096
2217
  }
2097
2218
  Modal.displayName = "Modal";
2098
2219
  var modal_default = Modal;
@@ -2209,12 +2330,13 @@ function Popover({ trigger, children, content, position = "bottom", className =
2209
2330
  }
2210
2331
  Popover.displayName = "Popover";
2211
2332
  var popover_default = Popover;
2212
- function Alert({ children, type = "info", dismissible = false, onClose, className = "" }) {
2333
+ function Alert({ children, type = "info", dismissible = false, onClose, className = "", position = "relative", duration = 0 }) {
2334
+ const [isClosing, setIsClosing] = useState(false);
2213
2335
  const typeClasses = {
2214
- info: "bg-info/10 text-foreground border-info/30",
2215
- success: "bg-success/10 text-foreground border-success/30",
2216
- warning: "bg-warning/10 text-foreground border-warning/30",
2217
- error: "bg-destructive/10 text-foreground border-destructive/30"
2336
+ info: "bg-info/20 text-foreground border-info/50 backdrop-blur-sm",
2337
+ success: "bg-success/20 text-foreground border-success/50 backdrop-blur-sm",
2338
+ warning: "bg-warning/20 text-foreground border-warning/50 backdrop-blur-sm",
2339
+ error: "bg-destructive/20 text-foreground border-destructive/50 backdrop-blur-sm"
2218
2340
  };
2219
2341
  const iconClasses = {
2220
2342
  info: "text-info",
@@ -2222,6 +2344,21 @@ function Alert({ children, type = "info", dismissible = false, onClose, classNam
2222
2344
  warning: "text-warning",
2223
2345
  error: "text-destructive"
2224
2346
  };
2347
+ const handleClose = useCallback(() => {
2348
+ setIsClosing(true);
2349
+ setTimeout(() => {
2350
+ onClose?.();
2351
+ }, 300);
2352
+ }, [onClose]);
2353
+ useEffect(() => {
2354
+ if (duration > 0 && onClose) {
2355
+ const timer = setTimeout(() => {
2356
+ handleClose();
2357
+ }, duration);
2358
+ return () => clearTimeout(timer);
2359
+ }
2360
+ return void 0;
2361
+ }, [duration, onClose, handleClose]);
2225
2362
  const icons = {
2226
2363
  info: /* @__PURE__ */ jsx("svg", { className: "w-5 h-5 flex-shrink-0", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx(
2227
2364
  "path",
@@ -2256,19 +2393,44 @@ function Alert({ children, type = "info", dismissible = false, onClose, classNam
2256
2393
  }
2257
2394
  ) })
2258
2395
  };
2259
- return /* @__PURE__ */ jsxs("div", { role: "alert", className: `p-4 border rounded-lg flex items-start gap-3 ${typeClasses[type]} ${className}`, children: [
2260
- /* @__PURE__ */ jsx("span", { className: iconClasses[type], children: icons[type] }),
2261
- /* @__PURE__ */ jsx("span", { className: "flex-1 text-sm", children }),
2262
- dismissible && onClose && /* @__PURE__ */ jsx(
2263
- "button",
2264
- {
2265
- onClick: onClose,
2266
- 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",
2267
- "aria-label": "Close alert",
2268
- 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" }) })
2269
- }
2270
- )
2271
- ] });
2396
+ const positionClasses = {
2397
+ top: "fixed top-4 left-1/2 -translate-x-1/2 z-[9999] max-w-2xl w-full mx-4",
2398
+ bottom: "fixed bottom-4 left-1/2 -translate-x-1/2 z-[9999] max-w-2xl w-full mx-4",
2399
+ relative: ""
2400
+ };
2401
+ const getAnimationClasses = () => {
2402
+ if (position === "top") {
2403
+ return isClosing ? "opacity-0 -translate-y-full" : "opacity-100 translate-y-0 animate-slideInTop";
2404
+ }
2405
+ if (position === "bottom") {
2406
+ return isClosing ? "opacity-0 translate-y-full" : "opacity-100 translate-y-0 animate-slideInBottom";
2407
+ }
2408
+ return isClosing ? "opacity-0" : "opacity-100";
2409
+ };
2410
+ const alertContent = /* @__PURE__ */ jsxs(
2411
+ "div",
2412
+ {
2413
+ role: "alert",
2414
+ className: `p-4 border rounded-lg flex items-start gap-3 transition-all duration-300 ease-out ${typeClasses[type]} ${positionClasses[position]} ${getAnimationClasses()} ${className}`,
2415
+ children: [
2416
+ /* @__PURE__ */ jsx("span", { className: iconClasses[type], children: icons[type] }),
2417
+ /* @__PURE__ */ jsx("span", { className: "flex-1 text-sm", children }),
2418
+ dismissible && onClose && /* @__PURE__ */ jsx(
2419
+ "button",
2420
+ {
2421
+ onClick: handleClose,
2422
+ 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",
2423
+ "aria-label": "Close alert",
2424
+ 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" }) })
2425
+ }
2426
+ )
2427
+ ]
2428
+ }
2429
+ );
2430
+ if (position !== "relative" && typeof document !== "undefined") {
2431
+ return createPortal(alertContent, document.body);
2432
+ }
2433
+ return alertContent;
2272
2434
  }
2273
2435
  Alert.displayName = "Alert";
2274
2436
  var alert_default = Alert;
@@ -3385,7 +3547,7 @@ function Drawer({
3385
3547
  closeOnEscape = true,
3386
3548
  closeOnOutside = true,
3387
3549
  unmountOnExit = true,
3388
- portalRoot = typeof document !== "undefined" ? document.body : null,
3550
+ portalRoot = portal_default(),
3389
3551
  noAnimation = false
3390
3552
  }) {
3391
3553
  const { phase, shouldRender, ref, getPhaseClass } = useOverlay_default({
@@ -3394,8 +3556,8 @@ function Drawer({
3394
3556
  restoreFocus: true,
3395
3557
  focusTrap: true,
3396
3558
  unmountOnExit,
3397
- exitDuration: noAnimation ? 0 : 300,
3398
- animationFrames: noAnimation ? 0 : 2
3559
+ exitDuration: noAnimation ? 0 : 250,
3560
+ animationFrames: noAnimation ? 0 : 0
3399
3561
  });
3400
3562
  if (!shouldRender) return null;
3401
3563
  const sizeClasses = {
@@ -3419,7 +3581,7 @@ function Drawer({
3419
3581
  };
3420
3582
  const openTransform = "translate-x-0 translate-y-0";
3421
3583
  const panelTransform = noAnimation ? "" : getPhaseClass(openTransform, closedTransform[position]);
3422
- const overlayOpacity = noAnimation ? "" : getPhaseClass("opacity-100", "opacity-0");
3584
+ const overlayOpacity = noAnimation ? "opacity-100" : getPhaseClass("opacity-100", "opacity-0");
3423
3585
  const handleKeyDown = (e) => {
3424
3586
  if (e.key === "Escape" && closeOnEscape) {
3425
3587
  e.stopPropagation();
@@ -3428,11 +3590,21 @@ function Drawer({
3428
3590
  };
3429
3591
  const panel = /* @__PURE__ */ jsxs(Fragment, { children: [
3430
3592
  /* @__PURE__ */ jsx(
3431
- "div",
3593
+ "button",
3432
3594
  {
3433
- className: `fixed inset-0 z-40 bg-black/50 backdrop-blur-sm transition-opacity duration-300 ${overlayOpacity}`,
3434
- "aria-hidden": "true",
3595
+ type: "button",
3596
+ 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`,
3597
+ "aria-label": closeOnOutside ? "Close overlay" : void 0,
3598
+ "aria-hidden": !closeOnOutside,
3599
+ tabIndex: closeOnOutside ? 0 : -1,
3435
3600
  onClick: () => closeOnOutside && onClose(),
3601
+ onKeyDown: (e) => {
3602
+ if (!closeOnOutside) return;
3603
+ if (e.key === "Enter" || e.key === " ") {
3604
+ e.preventDefault();
3605
+ onClose();
3606
+ }
3607
+ },
3436
3608
  "data-phase": phase
3437
3609
  }
3438
3610
  ),
@@ -3446,7 +3618,7 @@ function Drawer({
3446
3618
  tabIndex: -1,
3447
3619
  "data-phase": phase,
3448
3620
  "data-position": position,
3449
- className: `fixed ${edgeClasses[position]} ${position === "left" || position === "right" ? sizeClasses[size] : ""} bg-card text-card-foreground shadow-2xl z-50 flex flex-col outline-none ${panelTransform} ${noAnimation ? "" : "transition-[transform] duration-300 ease-out"} ${className}`,
3621
+ 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
3622
  onKeyDown: handleKeyDown,
3451
3623
  children: [
3452
3624
  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 +3898,14 @@ function useScrollReset(deps, container) {
3726
3898
  let cancelled = false;
3727
3899
  const maxRaf = 6;
3728
3900
  let rafCount = 0;
3901
+ const isRef = (obj) => {
3902
+ return typeof obj === "object" && obj !== null && "current" in obj;
3903
+ };
3729
3904
  const setAllScrollTop = () => {
3730
3905
  if (cancelled) return;
3731
3906
  window.scrollTo(0, 0);
3732
- if (container) container.scrollTop = 0;
3907
+ const resolved = isRef(container) ? container.current : container;
3908
+ if (resolved) resolved.scrollTop = 0;
3733
3909
  document.documentElement.scrollTop = 0;
3734
3910
  document.body.scrollTop = 0;
3735
3911
  };
@@ -3796,7 +3972,7 @@ function LeftNavLayout({
3796
3972
  navRef.current.scrollTop = scrollPosRef.current;
3797
3973
  }
3798
3974
  }, [children]);
3799
- useScrollReset_default([children], contentRef.current);
3975
+ useScrollReset_default([children], contentRef);
3800
3976
  const containerClasses = embedded ? "flex bg-background border border-border rounded-lg overflow-hidden" : "flex h-[calc(100vh-4rem)] bg-background";
3801
3977
  return /* @__PURE__ */ jsxs("div", { className: `${containerClasses} ${className}`, children: [
3802
3978
  mobileCollapsible && mobileMenuOpen && /* @__PURE__ */ jsx(