@hyddenlabs/hydn-ui 0.3.0-alpha.190 → 0.3.0-alpha.191

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
@@ -1707,12 +1707,10 @@ type LeftNavLayoutProps = {
1707
1707
  navWidth?: string;
1708
1708
  /** Width of the sidebar when collapsed */
1709
1709
  navWidthCollapsed?: string;
1710
- /** Whether sidebar is collapsible on mobile (becomes overlay) */
1711
- mobileCollapsible?: boolean;
1712
- /** Mobile menu open state (controlled) */
1713
- mobileMenuOpen?: boolean;
1714
- /** Callback when mobile menu state changes */
1715
- onMobileMenuOpenChange?: (open: boolean) => void;
1710
+ /** Hide navigation on mobile (slides in as overlay when toggled) */
1711
+ hideOnMobile?: boolean;
1712
+ /** Auto-collapse to icon-only mode on mobile screens */
1713
+ autoCollapseOnMobile?: boolean;
1716
1714
  /** Embedded demo mode (no fixed positioning, constrained height) */
1717
1715
  embedded?: boolean;
1718
1716
  /** Ref for the main content scrollable element */
@@ -1748,7 +1746,7 @@ type LeftNavLayoutProps = {
1748
1746
  * </LeftNavLayout>
1749
1747
  * ```
1750
1748
  */
1751
- declare function LeftNavLayout({ nav, children, collapsed: controlledCollapsed, onCollapsedChange, showToggle, className, navClassName, contentClassName, navWidth, navWidthCollapsed, mobileCollapsible, mobileMenuOpen: controlledMobileMenuOpen, embedded, header, mainContentRef }: Readonly<LeftNavLayoutProps>): react_jsx_runtime.JSX.Element;
1749
+ declare function LeftNavLayout({ nav, children, collapsed: controlledCollapsed, onCollapsedChange, showToggle, className, navClassName, contentClassName, navWidth, navWidthCollapsed, hideOnMobile, autoCollapseOnMobile, embedded, header, mainContentRef }: Readonly<LeftNavLayoutProps>): react_jsx_runtime.JSX.Element;
1752
1750
  declare namespace LeftNavLayout {
1753
1751
  var displayName: string;
1754
1752
  }
package/dist/index.d.ts CHANGED
@@ -1707,12 +1707,10 @@ type LeftNavLayoutProps = {
1707
1707
  navWidth?: string;
1708
1708
  /** Width of the sidebar when collapsed */
1709
1709
  navWidthCollapsed?: string;
1710
- /** Whether sidebar is collapsible on mobile (becomes overlay) */
1711
- mobileCollapsible?: boolean;
1712
- /** Mobile menu open state (controlled) */
1713
- mobileMenuOpen?: boolean;
1714
- /** Callback when mobile menu state changes */
1715
- onMobileMenuOpenChange?: (open: boolean) => void;
1710
+ /** Hide navigation on mobile (slides in as overlay when toggled) */
1711
+ hideOnMobile?: boolean;
1712
+ /** Auto-collapse to icon-only mode on mobile screens */
1713
+ autoCollapseOnMobile?: boolean;
1716
1714
  /** Embedded demo mode (no fixed positioning, constrained height) */
1717
1715
  embedded?: boolean;
1718
1716
  /** Ref for the main content scrollable element */
@@ -1748,7 +1746,7 @@ type LeftNavLayoutProps = {
1748
1746
  * </LeftNavLayout>
1749
1747
  * ```
1750
1748
  */
1751
- declare function LeftNavLayout({ nav, children, collapsed: controlledCollapsed, onCollapsedChange, showToggle, className, navClassName, contentClassName, navWidth, navWidthCollapsed, mobileCollapsible, mobileMenuOpen: controlledMobileMenuOpen, embedded, header, mainContentRef }: Readonly<LeftNavLayoutProps>): react_jsx_runtime.JSX.Element;
1749
+ declare function LeftNavLayout({ nav, children, collapsed: controlledCollapsed, onCollapsedChange, showToggle, className, navClassName, contentClassName, navWidth, navWidthCollapsed, hideOnMobile, autoCollapseOnMobile, embedded, header, mainContentRef }: Readonly<LeftNavLayoutProps>): react_jsx_runtime.JSX.Element;
1752
1750
  declare namespace LeftNavLayout {
1753
1751
  var displayName: string;
1754
1752
  }
package/dist/index.js CHANGED
@@ -2313,17 +2313,44 @@ function LeftNavLayout({
2313
2313
  contentClassName = "",
2314
2314
  navWidth = "16rem",
2315
2315
  navWidthCollapsed = "4.5rem",
2316
- mobileCollapsible = true,
2317
- mobileMenuOpen: controlledMobileMenuOpen,
2316
+ hideOnMobile = false,
2317
+ autoCollapseOnMobile = true,
2318
2318
  embedded = false,
2319
2319
  header = "Navigation",
2320
2320
  mainContentRef
2321
2321
  }) {
2322
2322
  const [internalCollapsed, setInternalCollapsed] = useState(false);
2323
+ const [mobileMenuOpen, setMobileMenuOpen] = useState(!hideOnMobile);
2324
+ const [isMobile, setIsMobile] = useState(false);
2325
+ const [mobileCollapsedOverride, setMobileCollapsedOverride] = useState(null);
2326
+ const desktopCollapsedRef = useRef(void 0);
2323
2327
  const navRef = useRef(null);
2324
2328
  const scrollPosRef = useRef(0);
2325
2329
  const internalContentRef = useRef(null);
2326
2330
  const contentRef = mainContentRef || internalContentRef;
2331
+ useEffect(() => {
2332
+ const checkMobile = () => {
2333
+ const newIsMobile = window.innerWidth < 1024;
2334
+ if (newIsMobile !== isMobile) {
2335
+ const wasDesktop = !isMobile;
2336
+ const isNowDesktop = !newIsMobile;
2337
+ setIsMobile(newIsMobile);
2338
+ if (wasDesktop && autoCollapseOnMobile) {
2339
+ const currentCollapsed = controlledCollapsed ?? internalCollapsed;
2340
+ desktopCollapsedRef.current = currentCollapsed;
2341
+ }
2342
+ if (isNowDesktop && autoCollapseOnMobile && desktopCollapsedRef.current !== void 0) {
2343
+ if (controlledCollapsed === void 0) {
2344
+ setInternalCollapsed(desktopCollapsedRef.current);
2345
+ }
2346
+ }
2347
+ setMobileCollapsedOverride(null);
2348
+ }
2349
+ };
2350
+ checkMobile();
2351
+ window.addEventListener("resize", checkMobile);
2352
+ return () => window.removeEventListener("resize", checkMobile);
2353
+ }, [isMobile, autoCollapseOnMobile, controlledCollapsed, internalCollapsed]);
2327
2354
  const collapsed = controlledCollapsed ?? internalCollapsed;
2328
2355
  const setCollapsed = (value) => {
2329
2356
  if (onCollapsedChange) {
@@ -2332,8 +2359,18 @@ function LeftNavLayout({
2332
2359
  setInternalCollapsed(value);
2333
2360
  }
2334
2361
  };
2335
- const mobileMenuOpen = controlledMobileMenuOpen ?? false;
2362
+ const effectiveCollapsed = autoCollapseOnMobile && isMobile ? mobileCollapsedOverride !== null ? mobileCollapsedOverride : true : collapsed;
2336
2363
  const toggleCollapsed = () => setCollapsed(!collapsed);
2364
+ const closeMobileMenu = () => setMobileMenuOpen(false);
2365
+ const handleToggleClick = () => {
2366
+ if (hideOnMobile && isMobile) {
2367
+ closeMobileMenu();
2368
+ } else if (autoCollapseOnMobile && isMobile) {
2369
+ setMobileCollapsedOverride(!effectiveCollapsed);
2370
+ } else {
2371
+ toggleCollapsed();
2372
+ }
2373
+ };
2337
2374
  useEffect(() => {
2338
2375
  if (navRef.current) {
2339
2376
  navRef.current.scrollTop = scrollPosRef.current;
@@ -2342,20 +2379,28 @@ function LeftNavLayout({
2342
2379
  useScrollReset_default([children], contentRef);
2343
2380
  const containerClasses = embedded ? "flex bg-background border border-border rounded-lg overflow-hidden" : "flex h-[calc(100vh-3.5rem)] md:h-[calc(100vh-4rem)] bg-background";
2344
2381
  return /* @__PURE__ */ jsxs("div", { className: `${containerClasses} ${className}`, children: [
2382
+ !embedded && hideOnMobile && mobileMenuOpen && /* @__PURE__ */ jsx(
2383
+ "div",
2384
+ {
2385
+ className: "fixed inset-0 bg-black/50 z-30 lg:hidden transition-opacity duration-300",
2386
+ onClick: closeMobileMenu,
2387
+ "aria-hidden": "true"
2388
+ }
2389
+ ),
2345
2390
  /* @__PURE__ */ jsx(
2346
2391
  "aside",
2347
2392
  {
2348
2393
  className: `
2349
- ${embedded ? "relative flex flex-col h-full" : "fixed lg:relative top-14 md:top-16 lg:top-0 left-0 z-40 lg:z-10 h-[calc(100vh-3.5rem)] md:h-[calc(100vh-4rem)] lg:h-full"}
2394
+ ${embedded ? "relative flex flex-col h-full" : hideOnMobile ? "fixed lg:relative top-14 md:top-16 lg:top-0 left-0 z-40 lg:z-10 h-[calc(100vh-3.5rem)] md:h-[calc(100vh-4rem)] lg:h-full" : "relative h-full"}
2350
2395
  flex flex-col shrink-0
2351
2396
  bg-background border-r border-border
2352
2397
  transition-all duration-300 ease-in-out
2353
- ${!embedded && mobileCollapsible && !mobileMenuOpen ? "-translate-x-full lg:translate-x-0" : "translate-x-0"}
2354
- ${collapsed ? "w-18" : "w-64"}
2398
+ ${!embedded && hideOnMobile && !mobileMenuOpen ? "-translate-x-full lg:translate-x-0" : "translate-x-0"}
2399
+ ${effectiveCollapsed ? "w-18" : "w-64"}
2355
2400
  ${navClassName}
2356
2401
  `,
2357
- style: !collapsed && navWidth !== "16rem" || collapsed && navWidthCollapsed !== "4.5rem" ? {
2358
- width: collapsed ? navWidthCollapsed : navWidth
2402
+ style: !effectiveCollapsed && navWidth !== "16rem" || effectiveCollapsed && navWidthCollapsed !== "4.5rem" ? {
2403
+ width: effectiveCollapsed ? navWidthCollapsed : navWidth
2359
2404
  } : void 0,
2360
2405
  "aria-label": "Main navigation",
2361
2406
  children: /* @__PURE__ */ jsxs(
@@ -2363,7 +2408,7 @@ function LeftNavLayout({
2363
2408
  {
2364
2409
  ref: navRef,
2365
2410
  className: "flex-1 overflow-y-auto overflow-x-hidden scrollbar-thin",
2366
- "data-collapsed": collapsed,
2411
+ "data-collapsed": effectiveCollapsed,
2367
2412
  onScroll: (e) => {
2368
2413
  scrollPosRef.current = e.currentTarget.scrollTop;
2369
2414
  },
@@ -2382,26 +2427,26 @@ function LeftNavLayout({
2382
2427
  className: `
2383
2428
  text-sm font-semibold text-foreground
2384
2429
  transition-all duration-300 ease-in-out
2385
- ${collapsed ? "opacity-0 w-0 overflow-hidden" : "opacity-100"}
2430
+ ${effectiveCollapsed ? "opacity-0 w-0 overflow-hidden" : "opacity-100"}
2386
2431
  `,
2387
- "aria-hidden": collapsed,
2432
+ "aria-hidden": effectiveCollapsed,
2388
2433
  children: header
2389
2434
  }
2390
2435
  ),
2391
2436
  /* @__PURE__ */ jsx(
2392
2437
  icon_button_default,
2393
2438
  {
2394
- icon: collapsed ? "layout-sidebar-left-expand" : "layout-sidebar-left-collapse",
2395
- hoverIcon: collapsed ? "layout-sidebar-left-expand-filled" : "layout-sidebar-left-collapse-filled",
2396
- ariaLabel: collapsed ? "Expand sidebar" : "Collapse sidebar",
2439
+ icon: effectiveCollapsed ? "layout-sidebar-left-expand" : "layout-sidebar-left-collapse",
2440
+ hoverIcon: effectiveCollapsed ? "layout-sidebar-left-expand-filled" : "layout-sidebar-left-collapse-filled",
2441
+ ariaLabel: effectiveCollapsed ? "Expand sidebar" : "Collapse sidebar",
2397
2442
  buttonStyle: "ghost",
2398
2443
  variant: "neutral",
2399
2444
  size: "sm",
2400
2445
  iconSize: "sm",
2401
2446
  className: `
2402
- ${collapsed ? "absolute left-1/2 -translate-x-1/2" : "absolute right-0"}
2447
+ ${effectiveCollapsed ? "absolute left-1/2 -translate-x-1/2" : "absolute right-0"}
2403
2448
  `,
2404
- onClick: toggleCollapsed
2449
+ onClick: handleToggleClick
2405
2450
  }
2406
2451
  )
2407
2452
  ]