@scripso-homepad/ui 0.4.15 → 0.4.17

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.
@@ -91,11 +91,20 @@ type SidebarProps = {
91
91
  branding: AdminSidebarBranding;
92
92
  labels: AdminSidebarLabels;
93
93
  sidebarStorageKey: string;
94
+ /**
95
+ * Current location pathname from the host app router.
96
+ * Pass `useLocation().pathname` from the app that owns `BrowserRouter`.
97
+ */
98
+ pathname: string;
94
99
  user?: AdminSidebarUser;
95
100
  onLogout?: () => void;
96
101
  className?: string;
97
102
  mobileOpen: boolean;
98
103
  onMobileClose?: () => void;
104
+ /**
105
+ * Host-owned navigation. Call `navigate(item.to)` from the app router here.
106
+ * The sidebar never imports react-router, so this must perform the route change.
107
+ */
99
108
  onNavItemClick?: (item: AdminNavItem) => void;
100
109
  collapseIcon?: ReactNode;
101
110
  expandIcon?: ReactNode;
@@ -104,7 +113,7 @@ type SidebarProps = {
104
113
  collapsed?: boolean;
105
114
  onCollapsedChange?: (collapsed: boolean) => void;
106
115
  };
107
- declare function Sidebar({ navItems, footerNavItems, branding, labels, sidebarStorageKey, user, onLogout, className, mobileOpen, onMobileClose, onNavItemClick, collapseIcon, expandIcon, closeIcon, initialCollapsed, collapsed, onCollapsedChange, }: SidebarProps): react.JSX.Element;
116
+ declare function Sidebar({ navItems, footerNavItems, branding, labels, sidebarStorageKey, pathname, user, onLogout, className, mobileOpen, onMobileClose, onNavItemClick, collapseIcon, expandIcon, closeIcon, initialCollapsed, collapsed, onCollapsedChange, }: SidebarProps): react.JSX.Element;
108
117
 
109
118
  type SidebarMobileHeaderProps = {
110
119
  branding: Pick<AdminSidebarBranding, 'logoIconSrc' | 'logoTitle' | 'logoTagline'>;
@@ -128,9 +137,16 @@ declare function DashboardLayout({ sidebar, header, mobileHeader, children, clas
128
137
  type SidebarNavItemProps = {
129
138
  item: AdminNavItem;
130
139
  isOpen: boolean;
140
+ isActive: boolean;
131
141
  onNavigate?: (item: AdminNavItem) => void;
132
142
  };
133
- declare function SidebarNavItem({ item, isOpen, onNavigate }: SidebarNavItemProps): react.JSX.Element | null;
143
+ declare function SidebarNavItem({ item, isOpen, isActive, onNavigate }: SidebarNavItemProps): react.JSX.Element | null;
144
+
145
+ /**
146
+ * Matches React Router `<NavLink end>` semantics using a host-provided pathname.
147
+ * Keeps `@scripso-homepad/ui` free of react-router so apps never get duplicate contexts.
148
+ */
149
+ declare function isNavItemActive(pathname: string, item: Pick<AdminNavItem, 'to' | 'end'>): boolean;
134
150
 
135
151
  type SidebarUserCardProps = {
136
152
  user: AdminSidebarUser;
@@ -254,7 +270,7 @@ type TableActionsMenuProps = {
254
270
  menuClassName?: string;
255
271
  /** Dropdown menu width in pixels. Defaults to 231. Ignored when menuFitContent is true. */
256
272
  menuWidth?: number;
257
- /** Size the menu to its content width instead of a fixed pixel width. */
273
+ /** Size the menu to its content width instead of a fixed pixel width. Defaults to true so labels stay on one line. */
258
274
  menuFitContent?: boolean;
259
275
  };
260
276
  declare function TableActionsMenu({ items, triggerAriaLabel, className, menuClassName, menuWidth, menuFitContent, }: TableActionsMenuProps): react.JSX.Element | null;
@@ -494,13 +510,15 @@ type ConfirmModalProps = {
494
510
  confirmText: string;
495
511
  onCancel: () => void;
496
512
  onConfirm: () => void;
513
+ /** Optional centered icon above the title (e.g. trash for delete confirmations). */
514
+ icon?: ReactNode;
497
515
  cancelDisabled?: boolean;
498
516
  confirmDisabled?: boolean;
499
517
  closeOnBackdrop?: boolean;
500
518
  containerClassName?: string;
501
519
  buttonClassName?: string;
502
520
  };
503
- declare function ConfirmModal({ open, title, description, cancelText, confirmText, onCancel, onConfirm, cancelDisabled, confirmDisabled, closeOnBackdrop, containerClassName, buttonClassName, }: ConfirmModalProps): react.JSX.Element | null;
521
+ declare function ConfirmModal({ open, title, description, cancelText, confirmText, onCancel, onConfirm, icon, cancelDisabled, confirmDisabled, closeOnBackdrop, containerClassName, buttonClassName, }: ConfirmModalProps): react.JSX.Element | null;
504
522
 
505
523
  declare function useMediaQuery(query: string): boolean;
506
524
 
@@ -509,4 +527,4 @@ declare function useOnClickOutside<T extends HTMLElement>(ref: OutsideTarget<T>,
509
527
 
510
528
  declare function cn(...inputs: ClassValue[]): string;
511
529
 
512
- export { type AdminBuildingOption, type AdminHeaderLabels, type AdminLayoutLabels, type AdminNavItem, type AdminSidebarBranding, type AdminSidebarLabels, type AdminSidebarUser, AppHeader, type AppHeaderProps, Badge, type BadgeProps, type BadgeVariant, BellIcon, BuildingIcon, BuildingSelect, type BuildingSelectProps, ConfirmModal, type ConfirmModalProps, DEFAULT_TABLE_BODY_MIN_HEIGHT, DashboardLayout, type DashboardLayoutProps, DataTable, type DataTableClassNames, type DataTableProps, Drawer, type DrawerProps, HistoryTimeline, type HistoryTimelineItem, type HistoryTimelineProps, type HomepadToasterProps, Modal, type ModalFooterAlign, type ModalFooterLayout, type ModalProps, type MutationToastMessages, type MutationToastResult, Pagination, type PaginationLabels, type PaginationProps, type PaginationVariant, type RunMutationWithToastOptions, Sidebar, SidebarMobileHeader, type SidebarMobileHeaderProps, SidebarNavItem, type SidebarNavItemProps, type SidebarProps, SidebarUserCard, type SidebarUserCardProps, StatusBadge, type StatusBadgeProps, type StatusBadgeTone, Table, TableActionButton, type TableActionButtonProps, type TableActionButtonVariant, TableActionsCell, type TableActionsCellProps, TableActionsMenu, type TableActionsMenuItem, type TableActionsMenuItemTone, type TableActionsMenuProps, TableBody, type TableBodyProps, TableCell, type TableCellProps, type TableCellVariant, TableHead, type TableHeadProps, TableHeader, type TableHeaderProps, TableIconText, type TableIconTextProps, TableMenuActivateIcon, TableMenuCheckIcon, TableMenuCloseIcon, TableMenuEditIcon, TableMenuInfoIcon, TableMenuRefreshIcon, TableMenuSuspendIcon, TableMenuTrashIcon, TableMoreIcon, type TableProps, TableRow, type TableRowActionsConfig, type TableRowProps, TableRowStatusActions, type TableRowStatusActionsProps, TableScrollArea, type TableScrollAreaProps, type TableSortDirection, TableSortIcon, TableStatusActionsCell, type TableStatusActionsCellProps, Toaster, ToasterProvider, cn, getPaginationRange, getTotalPages, getVisiblePageNumbers, runMutationWithToast, tableRowDisabledCellClassName, useMediaQuery, useOnClickOutside };
530
+ export { type AdminBuildingOption, type AdminHeaderLabels, type AdminLayoutLabels, type AdminNavItem, type AdminSidebarBranding, type AdminSidebarLabels, type AdminSidebarUser, AppHeader, type AppHeaderProps, Badge, type BadgeProps, type BadgeVariant, BellIcon, BuildingIcon, BuildingSelect, type BuildingSelectProps, ConfirmModal, type ConfirmModalProps, DEFAULT_TABLE_BODY_MIN_HEIGHT, DashboardLayout, type DashboardLayoutProps, DataTable, type DataTableClassNames, type DataTableProps, Drawer, type DrawerProps, HistoryTimeline, type HistoryTimelineItem, type HistoryTimelineProps, type HomepadToasterProps, Modal, type ModalFooterAlign, type ModalFooterLayout, type ModalProps, type MutationToastMessages, type MutationToastResult, Pagination, type PaginationLabels, type PaginationProps, type PaginationVariant, type RunMutationWithToastOptions, Sidebar, SidebarMobileHeader, type SidebarMobileHeaderProps, SidebarNavItem, type SidebarNavItemProps, type SidebarProps, SidebarUserCard, type SidebarUserCardProps, StatusBadge, type StatusBadgeProps, type StatusBadgeTone, Table, TableActionButton, type TableActionButtonProps, type TableActionButtonVariant, TableActionsCell, type TableActionsCellProps, TableActionsMenu, type TableActionsMenuItem, type TableActionsMenuItemTone, type TableActionsMenuProps, TableBody, type TableBodyProps, TableCell, type TableCellProps, type TableCellVariant, TableHead, type TableHeadProps, TableHeader, type TableHeaderProps, TableIconText, type TableIconTextProps, TableMenuActivateIcon, TableMenuCheckIcon, TableMenuCloseIcon, TableMenuEditIcon, TableMenuInfoIcon, TableMenuRefreshIcon, TableMenuSuspendIcon, TableMenuTrashIcon, TableMoreIcon, type TableProps, TableRow, type TableRowActionsConfig, type TableRowProps, TableRowStatusActions, type TableRowStatusActionsProps, TableScrollArea, type TableScrollAreaProps, type TableSortDirection, TableSortIcon, TableStatusActionsCell, type TableStatusActionsCellProps, Toaster, ToasterProvider, cn, getPaginationRange, getTotalPages, getVisiblePageNumbers, isNavItemActive, runMutationWithToast, tableRowDisabledCellClassName, useMediaQuery, useOnClickOutside };
@@ -91,11 +91,20 @@ type SidebarProps = {
91
91
  branding: AdminSidebarBranding;
92
92
  labels: AdminSidebarLabels;
93
93
  sidebarStorageKey: string;
94
+ /**
95
+ * Current location pathname from the host app router.
96
+ * Pass `useLocation().pathname` from the app that owns `BrowserRouter`.
97
+ */
98
+ pathname: string;
94
99
  user?: AdminSidebarUser;
95
100
  onLogout?: () => void;
96
101
  className?: string;
97
102
  mobileOpen: boolean;
98
103
  onMobileClose?: () => void;
104
+ /**
105
+ * Host-owned navigation. Call `navigate(item.to)` from the app router here.
106
+ * The sidebar never imports react-router, so this must perform the route change.
107
+ */
99
108
  onNavItemClick?: (item: AdminNavItem) => void;
100
109
  collapseIcon?: ReactNode;
101
110
  expandIcon?: ReactNode;
@@ -104,7 +113,7 @@ type SidebarProps = {
104
113
  collapsed?: boolean;
105
114
  onCollapsedChange?: (collapsed: boolean) => void;
106
115
  };
107
- declare function Sidebar({ navItems, footerNavItems, branding, labels, sidebarStorageKey, user, onLogout, className, mobileOpen, onMobileClose, onNavItemClick, collapseIcon, expandIcon, closeIcon, initialCollapsed, collapsed, onCollapsedChange, }: SidebarProps): react.JSX.Element;
116
+ declare function Sidebar({ navItems, footerNavItems, branding, labels, sidebarStorageKey, pathname, user, onLogout, className, mobileOpen, onMobileClose, onNavItemClick, collapseIcon, expandIcon, closeIcon, initialCollapsed, collapsed, onCollapsedChange, }: SidebarProps): react.JSX.Element;
108
117
 
109
118
  type SidebarMobileHeaderProps = {
110
119
  branding: Pick<AdminSidebarBranding, 'logoIconSrc' | 'logoTitle' | 'logoTagline'>;
@@ -128,9 +137,16 @@ declare function DashboardLayout({ sidebar, header, mobileHeader, children, clas
128
137
  type SidebarNavItemProps = {
129
138
  item: AdminNavItem;
130
139
  isOpen: boolean;
140
+ isActive: boolean;
131
141
  onNavigate?: (item: AdminNavItem) => void;
132
142
  };
133
- declare function SidebarNavItem({ item, isOpen, onNavigate }: SidebarNavItemProps): react.JSX.Element | null;
143
+ declare function SidebarNavItem({ item, isOpen, isActive, onNavigate }: SidebarNavItemProps): react.JSX.Element | null;
144
+
145
+ /**
146
+ * Matches React Router `<NavLink end>` semantics using a host-provided pathname.
147
+ * Keeps `@scripso-homepad/ui` free of react-router so apps never get duplicate contexts.
148
+ */
149
+ declare function isNavItemActive(pathname: string, item: Pick<AdminNavItem, 'to' | 'end'>): boolean;
134
150
 
135
151
  type SidebarUserCardProps = {
136
152
  user: AdminSidebarUser;
@@ -254,7 +270,7 @@ type TableActionsMenuProps = {
254
270
  menuClassName?: string;
255
271
  /** Dropdown menu width in pixels. Defaults to 231. Ignored when menuFitContent is true. */
256
272
  menuWidth?: number;
257
- /** Size the menu to its content width instead of a fixed pixel width. */
273
+ /** Size the menu to its content width instead of a fixed pixel width. Defaults to true so labels stay on one line. */
258
274
  menuFitContent?: boolean;
259
275
  };
260
276
  declare function TableActionsMenu({ items, triggerAriaLabel, className, menuClassName, menuWidth, menuFitContent, }: TableActionsMenuProps): react.JSX.Element | null;
@@ -494,13 +510,15 @@ type ConfirmModalProps = {
494
510
  confirmText: string;
495
511
  onCancel: () => void;
496
512
  onConfirm: () => void;
513
+ /** Optional centered icon above the title (e.g. trash for delete confirmations). */
514
+ icon?: ReactNode;
497
515
  cancelDisabled?: boolean;
498
516
  confirmDisabled?: boolean;
499
517
  closeOnBackdrop?: boolean;
500
518
  containerClassName?: string;
501
519
  buttonClassName?: string;
502
520
  };
503
- declare function ConfirmModal({ open, title, description, cancelText, confirmText, onCancel, onConfirm, cancelDisabled, confirmDisabled, closeOnBackdrop, containerClassName, buttonClassName, }: ConfirmModalProps): react.JSX.Element | null;
521
+ declare function ConfirmModal({ open, title, description, cancelText, confirmText, onCancel, onConfirm, icon, cancelDisabled, confirmDisabled, closeOnBackdrop, containerClassName, buttonClassName, }: ConfirmModalProps): react.JSX.Element | null;
504
522
 
505
523
  declare function useMediaQuery(query: string): boolean;
506
524
 
@@ -509,4 +527,4 @@ declare function useOnClickOutside<T extends HTMLElement>(ref: OutsideTarget<T>,
509
527
 
510
528
  declare function cn(...inputs: ClassValue[]): string;
511
529
 
512
- export { type AdminBuildingOption, type AdminHeaderLabels, type AdminLayoutLabels, type AdminNavItem, type AdminSidebarBranding, type AdminSidebarLabels, type AdminSidebarUser, AppHeader, type AppHeaderProps, Badge, type BadgeProps, type BadgeVariant, BellIcon, BuildingIcon, BuildingSelect, type BuildingSelectProps, ConfirmModal, type ConfirmModalProps, DEFAULT_TABLE_BODY_MIN_HEIGHT, DashboardLayout, type DashboardLayoutProps, DataTable, type DataTableClassNames, type DataTableProps, Drawer, type DrawerProps, HistoryTimeline, type HistoryTimelineItem, type HistoryTimelineProps, type HomepadToasterProps, Modal, type ModalFooterAlign, type ModalFooterLayout, type ModalProps, type MutationToastMessages, type MutationToastResult, Pagination, type PaginationLabels, type PaginationProps, type PaginationVariant, type RunMutationWithToastOptions, Sidebar, SidebarMobileHeader, type SidebarMobileHeaderProps, SidebarNavItem, type SidebarNavItemProps, type SidebarProps, SidebarUserCard, type SidebarUserCardProps, StatusBadge, type StatusBadgeProps, type StatusBadgeTone, Table, TableActionButton, type TableActionButtonProps, type TableActionButtonVariant, TableActionsCell, type TableActionsCellProps, TableActionsMenu, type TableActionsMenuItem, type TableActionsMenuItemTone, type TableActionsMenuProps, TableBody, type TableBodyProps, TableCell, type TableCellProps, type TableCellVariant, TableHead, type TableHeadProps, TableHeader, type TableHeaderProps, TableIconText, type TableIconTextProps, TableMenuActivateIcon, TableMenuCheckIcon, TableMenuCloseIcon, TableMenuEditIcon, TableMenuInfoIcon, TableMenuRefreshIcon, TableMenuSuspendIcon, TableMenuTrashIcon, TableMoreIcon, type TableProps, TableRow, type TableRowActionsConfig, type TableRowProps, TableRowStatusActions, type TableRowStatusActionsProps, TableScrollArea, type TableScrollAreaProps, type TableSortDirection, TableSortIcon, TableStatusActionsCell, type TableStatusActionsCellProps, Toaster, ToasterProvider, cn, getPaginationRange, getTotalPages, getVisiblePageNumbers, runMutationWithToast, tableRowDisabledCellClassName, useMediaQuery, useOnClickOutside };
530
+ export { type AdminBuildingOption, type AdminHeaderLabels, type AdminLayoutLabels, type AdminNavItem, type AdminSidebarBranding, type AdminSidebarLabels, type AdminSidebarUser, AppHeader, type AppHeaderProps, Badge, type BadgeProps, type BadgeVariant, BellIcon, BuildingIcon, BuildingSelect, type BuildingSelectProps, ConfirmModal, type ConfirmModalProps, DEFAULT_TABLE_BODY_MIN_HEIGHT, DashboardLayout, type DashboardLayoutProps, DataTable, type DataTableClassNames, type DataTableProps, Drawer, type DrawerProps, HistoryTimeline, type HistoryTimelineItem, type HistoryTimelineProps, type HomepadToasterProps, Modal, type ModalFooterAlign, type ModalFooterLayout, type ModalProps, type MutationToastMessages, type MutationToastResult, Pagination, type PaginationLabels, type PaginationProps, type PaginationVariant, type RunMutationWithToastOptions, Sidebar, SidebarMobileHeader, type SidebarMobileHeaderProps, SidebarNavItem, type SidebarNavItemProps, type SidebarProps, SidebarUserCard, type SidebarUserCardProps, StatusBadge, type StatusBadgeProps, type StatusBadgeTone, Table, TableActionButton, type TableActionButtonProps, type TableActionButtonVariant, TableActionsCell, type TableActionsCellProps, TableActionsMenu, type TableActionsMenuItem, type TableActionsMenuItemTone, type TableActionsMenuProps, TableBody, type TableBodyProps, TableCell, type TableCellProps, type TableCellVariant, TableHead, type TableHeadProps, TableHeader, type TableHeaderProps, TableIconText, type TableIconTextProps, TableMenuActivateIcon, TableMenuCheckIcon, TableMenuCloseIcon, TableMenuEditIcon, TableMenuInfoIcon, TableMenuRefreshIcon, TableMenuSuspendIcon, TableMenuTrashIcon, TableMoreIcon, type TableProps, TableRow, type TableRowActionsConfig, type TableRowProps, TableRowStatusActions, type TableRowStatusActionsProps, TableScrollArea, type TableScrollAreaProps, type TableSortDirection, TableSortIcon, TableStatusActionsCell, type TableStatusActionsCellProps, Toaster, ToasterProvider, cn, getPaginationRange, getTotalPages, getVisiblePageNumbers, isNavItemActive, runMutationWithToast, tableRowDisabledCellClassName, useMediaQuery, useOnClickOutside };
package/dist/web/index.js CHANGED
@@ -1,10 +1,9 @@
1
- import { __commonJS, __require, __toESM, Input, Button } from '../chunk-3G3ZKFHX.js';
1
+ import { __commonJS, __require, __toESM, Input, Button } from '../chunk-U7OSCJKA.js';
2
2
  import { ChevronsUpDown, Search, LogOut, PanelLeftClose, PanelLeftOpen, X, Menu, ChevronLeft, ChevronRight } from 'lucide-react';
3
3
  import { clsx } from 'clsx';
4
4
  import { twMerge } from 'tailwind-merge';
5
5
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
6
6
  import { createContext, forwardRef, useRef, useEffect, useState, useId, useCallback, useMemo, useContext, useLayoutEffect } from 'react';
7
- import { NavLink, useLocation } from 'react-router-dom';
8
7
  import { Toaster as Toaster$1, toast } from 'sonner';
9
8
  export { toast } from 'sonner';
10
9
  import 'sonner/dist/styles.css';
@@ -7371,7 +7370,7 @@ var require_react_dom_development = __commonJS({
7371
7370
  var HostPortal = 4;
7372
7371
  var HostComponent = 5;
7373
7372
  var HostText = 6;
7374
- var Fragment5 = 7;
7373
+ var Fragment4 = 7;
7375
7374
  var Mode = 8;
7376
7375
  var ContextConsumer = 9;
7377
7376
  var ContextProvider = 10;
@@ -8526,7 +8525,7 @@ var require_react_dom_development = __commonJS({
8526
8525
  return "DehydratedFragment";
8527
8526
  case ForwardRef:
8528
8527
  return getWrappedName$1(type, type.render, "ForwardRef");
8529
- case Fragment5:
8528
+ case Fragment4:
8530
8529
  return "Fragment";
8531
8530
  case HostComponent:
8532
8531
  return type;
@@ -16951,7 +16950,7 @@ var require_react_dom_development = __commonJS({
16951
16950
  }
16952
16951
  }
16953
16952
  function updateFragment2(returnFiber, current2, fragment, lanes, key) {
16954
- if (current2 === null || current2.tag !== Fragment5) {
16953
+ if (current2 === null || current2.tag !== Fragment4) {
16955
16954
  var created = createFiberFromFragment(fragment, returnFiber.mode, lanes, key);
16956
16955
  created.return = returnFiber;
16957
16956
  return created;
@@ -17354,7 +17353,7 @@ var require_react_dom_development = __commonJS({
17354
17353
  if (child.key === key) {
17355
17354
  var elementType = element.type;
17356
17355
  if (elementType === REACT_FRAGMENT_TYPE) {
17357
- if (child.tag === Fragment5) {
17356
+ if (child.tag === Fragment4) {
17358
17357
  deleteRemainingChildren(returnFiber, child.sibling);
17359
17358
  var existing = useFiber(child, element.props.children);
17360
17359
  existing.return = returnFiber;
@@ -22828,7 +22827,7 @@ var require_react_dom_development = __commonJS({
22828
22827
  var _resolvedProps2 = workInProgress2.elementType === type ? _unresolvedProps2 : resolveDefaultProps(type, _unresolvedProps2);
22829
22828
  return updateForwardRef(current2, workInProgress2, type, _resolvedProps2, renderLanes2);
22830
22829
  }
22831
- case Fragment5:
22830
+ case Fragment4:
22832
22831
  return updateFragment(current2, workInProgress2, renderLanes2);
22833
22832
  case Mode:
22834
22833
  return updateMode(current2, workInProgress2, renderLanes2);
@@ -23100,7 +23099,7 @@ var require_react_dom_development = __commonJS({
23100
23099
  case SimpleMemoComponent:
23101
23100
  case FunctionComponent:
23102
23101
  case ForwardRef:
23103
- case Fragment5:
23102
+ case Fragment4:
23104
23103
  case Mode:
23105
23104
  case Profiler:
23106
23105
  case ContextConsumer:
@@ -27352,7 +27351,7 @@ var require_react_dom_development = __commonJS({
27352
27351
  return fiber;
27353
27352
  }
27354
27353
  function createFiberFromFragment(elements, mode, lanes, key) {
27355
- var fiber = createFiber(Fragment5, elements, key, mode);
27354
+ var fiber = createFiber(Fragment4, elements, key, mode);
27356
27355
  fiber.lanes = lanes;
27357
27356
  return fiber;
27358
27357
  }
@@ -28875,29 +28874,42 @@ function useMediaQuery(query) {
28875
28874
  }, [query]);
28876
28875
  return matches;
28877
28876
  }
28878
- function SidebarNavItem({ item, isOpen, onNavigate }) {
28877
+
28878
+ // src/web/layout/nav-active.ts
28879
+ function isNavItemActive(pathname, item) {
28880
+ if (item.end) {
28881
+ return pathname === item.to;
28882
+ }
28883
+ return pathname === item.to || pathname.startsWith(`${item.to}/`);
28884
+ }
28885
+ function SidebarNavItem({ item, isOpen, isActive, onNavigate }) {
28879
28886
  if (item.hidden) {
28880
28887
  return null;
28881
28888
  }
28882
- const handleClick = () => {
28889
+ const handleClick = (event) => {
28890
+ event.preventDefault();
28891
+ if (item.disabled) {
28892
+ return;
28893
+ }
28883
28894
  item.onClick?.();
28884
28895
  onNavigate?.(item);
28885
28896
  };
28886
- return /* @__PURE__ */ jsx(
28887
- NavLink,
28897
+ return /* @__PURE__ */ jsxs(
28898
+ "button",
28888
28899
  {
28889
- to: item.to,
28890
- end: item.end,
28900
+ type: "button",
28891
28901
  onClick: handleClick,
28902
+ "aria-current": isActive ? "page" : void 0,
28892
28903
  "aria-disabled": item.disabled,
28904
+ disabled: item.disabled,
28893
28905
  tabIndex: item.disabled ? -1 : void 0,
28894
- className: ({ isActive }) => cn(
28906
+ className: cn(
28895
28907
  "relative flex items-center rounded-xl px-4 py-3 transition-[background-color,color,gap,padding] duration-300 ease-in-out",
28896
28908
  isOpen ? "w-full gap-4" : "justify-center gap-0 px-3",
28897
28909
  item.disabled && "pointer-events-none opacity-50",
28898
28910
  isActive ? "bg-black/12 text-white" : "text-navy-100 hover:bg-white/5"
28899
28911
  ),
28900
- children: ({ isActive }) => /* @__PURE__ */ jsxs(Fragment, { children: [
28912
+ children: [
28901
28913
  /* @__PURE__ */ jsx(
28902
28914
  "span",
28903
28915
  {
@@ -28919,7 +28931,7 @@ function SidebarNavItem({ item, isOpen, onNavigate }) {
28919
28931
  children: item.label
28920
28932
  }
28921
28933
  )
28922
- ] })
28934
+ ]
28923
28935
  }
28924
28936
  );
28925
28937
  }
@@ -28994,6 +29006,7 @@ function Sidebar({
28994
29006
  branding,
28995
29007
  labels,
28996
29008
  sidebarStorageKey,
29009
+ pathname,
28997
29010
  user,
28998
29011
  onLogout,
28999
29012
  className,
@@ -29007,7 +29020,6 @@ function Sidebar({
29007
29020
  collapsed,
29008
29021
  onCollapsedChange
29009
29022
  }) {
29010
- const location = useLocation();
29011
29023
  const isDesktop = useMediaQuery("(min-width: 768px)");
29012
29024
  const [internalCollapsed, setInternalCollapsed] = useState(
29013
29025
  () => readInitialCollapsedState(sidebarStorageKey, initialCollapsed)
@@ -29043,16 +29055,16 @@ function Sidebar({
29043
29055
  },
29044
29056
  [isDesktop, onMobileClose, onNavItemClick]
29045
29057
  );
29046
- const pathnameRef = useRef(location.pathname);
29058
+ const pathnameRef = useRef(pathname);
29047
29059
  useEffect(() => {
29048
- if (pathnameRef.current === location.pathname) {
29060
+ if (pathnameRef.current === pathname) {
29049
29061
  return;
29050
29062
  }
29051
- pathnameRef.current = location.pathname;
29063
+ pathnameRef.current = pathname;
29052
29064
  if (!isDesktop) {
29053
29065
  onMobileClose?.();
29054
29066
  }
29055
- }, [location.pathname, isDesktop, onMobileClose]);
29067
+ }, [pathname, isDesktop, onMobileClose]);
29056
29068
  useEffect(() => {
29057
29069
  if (!mobileOpen || isDesktop) {
29058
29070
  return;
@@ -29133,6 +29145,7 @@ function Sidebar({
29133
29145
  {
29134
29146
  item,
29135
29147
  isOpen: isExpanded,
29148
+ isActive: isNavItemActive(pathname, item),
29136
29149
  onNavigate: handleNavItemNavigate
29137
29150
  },
29138
29151
  item.to
@@ -29143,6 +29156,7 @@ function Sidebar({
29143
29156
  {
29144
29157
  item,
29145
29158
  isOpen: isExpanded,
29159
+ isActive: isNavItemActive(pathname, item),
29146
29160
  onNavigate: handleNavItemNavigate
29147
29161
  },
29148
29162
  item.to
@@ -29905,7 +29919,7 @@ function TableActionsMenu({
29905
29919
  className,
29906
29920
  menuClassName,
29907
29921
  menuWidth = MENU_WIDTH_PX,
29908
- menuFitContent = false
29922
+ menuFitContent = true
29909
29923
  }) {
29910
29924
  const [open, setOpen] = useState(false);
29911
29925
  const [menuPosition, setMenuPosition] = useState(null);
@@ -29918,11 +29932,14 @@ function TableActionsMenu({
29918
29932
  }, []);
29919
29933
  const updateMenuPosition = useCallback(() => {
29920
29934
  const trigger = triggerRef.current;
29935
+ const menuEl = menuRef.current;
29921
29936
  if (!trigger) {
29922
29937
  return;
29923
29938
  }
29924
29939
  const rect = trigger.getBoundingClientRect();
29925
- const resolvedMenuWidth = menuFitContent ? menuRef.current?.getBoundingClientRect().width ?? menuWidth : menuWidth;
29940
+ const viewportMaxWidth = typeof window === "undefined" ? menuWidth : Math.max(menuWidth, window.innerWidth - MENU_VIEWPORT_MARGIN_PX * 2);
29941
+ const measuredWidth = menuFitContent ? menuEl?.offsetWidth || menuEl?.getBoundingClientRect().width || menuWidth : menuWidth;
29942
+ const resolvedMenuWidth = Math.min(Math.max(measuredWidth, 1), viewportMaxWidth);
29926
29943
  setMenuPosition({
29927
29944
  top: rect.bottom + MENU_OFFSET_PX,
29928
29945
  left: clampMenuLeft(rect.right - resolvedMenuWidth, resolvedMenuWidth)
@@ -29935,13 +29952,7 @@ function TableActionsMenu({
29935
29952
  return;
29936
29953
  }
29937
29954
  updateMenuPosition();
29938
- }, [open, updateMenuPosition]);
29939
- useIsomorphicLayoutEffect(() => {
29940
- if (!open || !menuFitContent) {
29941
- return;
29942
- }
29943
- updateMenuPosition();
29944
- }, [items, menuFitContent, open, updateMenuPosition]);
29955
+ }, [open, items, menuFitContent, updateMenuPosition]);
29945
29956
  useEffect(() => {
29946
29957
  if (!open) {
29947
29958
  return;
@@ -29967,7 +29978,7 @@ function TableActionsMenu({
29967
29978
  if (items.length === 0) {
29968
29979
  return null;
29969
29980
  }
29970
- const menu = open && menuPosition != null ? /* @__PURE__ */ jsx(
29981
+ const menu = open ? /* @__PURE__ */ jsx(
29971
29982
  "div",
29972
29983
  {
29973
29984
  ref: menuRef,
@@ -29975,9 +29986,13 @@ function TableActionsMenu({
29975
29986
  role: "menu",
29976
29987
  style: {
29977
29988
  position: "fixed",
29978
- top: menuPosition.top,
29979
- left: menuPosition.left,
29980
- ...menuFitContent ? { width: "max-content" } : { width: menuWidth }
29989
+ top: menuPosition?.top ?? 0,
29990
+ left: menuPosition?.left ?? 0,
29991
+ maxWidth: `calc(100vw - ${MENU_VIEWPORT_MARGIN_PX * 2}px)`,
29992
+ ...menuFitContent ? { width: "max-content" } : { width: menuWidth },
29993
+ // Hide until we have a measured viewport-safe position.
29994
+ visibility: menuPosition != null ? "visible" : "hidden",
29995
+ pointerEvents: menuPosition != null ? "auto" : "none"
29981
29996
  },
29982
29997
  className: cn(
29983
29998
  "z-50 overflow-hidden rounded-2xl border border-storm-gray-50 bg-white shadow-[0_4px_20px_0_rgba(0,0,0,0.05)]",
@@ -29999,14 +30014,13 @@ function TableActionsMenu({
29999
30014
  item.onSelect();
30000
30015
  },
30001
30016
  className: cn(
30002
- "flex h-[51px] cursor-pointer items-center gap-2.5 px-3 text-left typography-14 font-medium text-storm-gray-900 transition-colors hover:bg-storm-gray-0",
30003
- menuFitContent ? "w-auto" : "w-full",
30017
+ "flex h-[51px] w-full cursor-pointer items-center gap-2.5 px-3 text-left typography-14 font-medium text-storm-gray-900 transition-colors hover:bg-storm-gray-0",
30004
30018
  index > 0 && "border-t border-storm-gray-50",
30005
30019
  item.disabled && "cursor-not-allowed opacity-50"
30006
30020
  ),
30007
30021
  children: [
30008
30022
  icon ? /* @__PURE__ */ jsx("span", { className: "inline-flex size-5 shrink-0 items-center justify-center text-storm-gray-200", children: icon }) : null,
30009
- /* @__PURE__ */ jsx("span", { children: item.label })
30023
+ /* @__PURE__ */ jsx("span", { className: "whitespace-nowrap", children: item.label })
30010
30024
  ]
30011
30025
  },
30012
30026
  item.id
@@ -30413,6 +30427,28 @@ function Modal({
30413
30427
  return typeof document !== "undefined" ? (0, import_react_dom2.createPortal)(modal, document.body) : modal;
30414
30428
  }
30415
30429
  var DRAWER_TRANSITION_MS = 300;
30430
+ var bodyScrollLockCount = 0;
30431
+ var previousBodyOverflow = "";
30432
+ function lockBodyScroll() {
30433
+ if (typeof document === "undefined") {
30434
+ return;
30435
+ }
30436
+ if (bodyScrollLockCount === 0) {
30437
+ previousBodyOverflow = document.body.style.overflow;
30438
+ document.body.style.overflow = "hidden";
30439
+ }
30440
+ bodyScrollLockCount += 1;
30441
+ }
30442
+ function unlockBodyScroll() {
30443
+ if (typeof document === "undefined") {
30444
+ return;
30445
+ }
30446
+ bodyScrollLockCount = Math.max(0, bodyScrollLockCount - 1);
30447
+ if (bodyScrollLockCount === 0) {
30448
+ document.body.style.overflow = previousBodyOverflow;
30449
+ previousBodyOverflow = "";
30450
+ }
30451
+ }
30416
30452
  function Drawer({
30417
30453
  open,
30418
30454
  title,
@@ -30453,8 +30489,7 @@ function Drawer({
30453
30489
  if (!isPresent) {
30454
30490
  return;
30455
30491
  }
30456
- const previousOverflow = document.body.style.overflow;
30457
- document.body.style.overflow = "hidden";
30492
+ lockBodyScroll();
30458
30493
  const handleKeyDown = (event) => {
30459
30494
  if (event.key === "Escape") {
30460
30495
  onClose();
@@ -30462,7 +30497,7 @@ function Drawer({
30462
30497
  };
30463
30498
  window.addEventListener("keydown", handleKeyDown);
30464
30499
  return () => {
30465
- document.body.style.overflow = previousOverflow;
30500
+ unlockBodyScroll();
30466
30501
  window.removeEventListener("keydown", handleKeyDown);
30467
30502
  };
30468
30503
  }, [isPresent, onClose]);
@@ -30808,6 +30843,7 @@ function ConfirmModal({
30808
30843
  confirmText,
30809
30844
  onCancel,
30810
30845
  onConfirm,
30846
+ icon,
30811
30847
  cancelDisabled = false,
30812
30848
  confirmDisabled = false,
30813
30849
  closeOnBackdrop = true,
@@ -30853,7 +30889,8 @@ function ConfirmModal({
30853
30889
  event.stopPropagation();
30854
30890
  },
30855
30891
  children: [
30856
- /* @__PURE__ */ jsxs("header", { className: "flex flex-col gap-3 text-center", children: [
30892
+ /* @__PURE__ */ jsxs("header", { className: "flex flex-col items-center gap-3 text-center", children: [
30893
+ icon ? /* @__PURE__ */ jsx("div", { className: "flex size-14 items-center justify-center rounded-2xl bg-storm-gray-50 text-storm-gray-500", children: icon }) : null,
30857
30894
  /* @__PURE__ */ jsx(
30858
30895
  "h2",
30859
30896
  {
@@ -30963,6 +31000,6 @@ react-dom/cjs/react-dom.development.js:
30963
31000
  *)
30964
31001
  */
30965
31002
 
30966
- export { AppHeader, Badge, BellIcon, BuildingIcon, BuildingSelect, ConfirmModal, DEFAULT_TABLE_BODY_MIN_HEIGHT, DashboardLayout, DataTable, Drawer, HistoryTimeline, Modal, Pagination, Sidebar, SidebarMobileHeader, SidebarNavItem, SidebarUserCard, StatusBadge, Table, TableActionButton, TableActionsCell, TableActionsMenu, TableBody, TableCell, TableHead, TableHeader, TableIconText, TableMenuActivateIcon, TableMenuCheckIcon, TableMenuCloseIcon, TableMenuEditIcon, TableMenuInfoIcon, TableMenuRefreshIcon, TableMenuSuspendIcon, TableMenuTrashIcon, TableMoreIcon, TableRow, TableRowStatusActions, TableScrollArea, TableSortIcon, TableStatusActionsCell, Toaster, ToasterProvider, cn, getPaginationRange, getTotalPages, getVisiblePageNumbers, runMutationWithToast, tableRowDisabledCellClassName, useMediaQuery, useOnClickOutside };
31003
+ export { AppHeader, Badge, BellIcon, BuildingIcon, BuildingSelect, ConfirmModal, DEFAULT_TABLE_BODY_MIN_HEIGHT, DashboardLayout, DataTable, Drawer, HistoryTimeline, Modal, Pagination, Sidebar, SidebarMobileHeader, SidebarNavItem, SidebarUserCard, StatusBadge, Table, TableActionButton, TableActionsCell, TableActionsMenu, TableBody, TableCell, TableHead, TableHeader, TableIconText, TableMenuActivateIcon, TableMenuCheckIcon, TableMenuCloseIcon, TableMenuEditIcon, TableMenuInfoIcon, TableMenuRefreshIcon, TableMenuSuspendIcon, TableMenuTrashIcon, TableMoreIcon, TableRow, TableRowStatusActions, TableScrollArea, TableSortIcon, TableStatusActionsCell, Toaster, ToasterProvider, cn, getPaginationRange, getTotalPages, getVisiblePageNumbers, isNavItemActive, runMutationWithToast, tableRowDisabledCellClassName, useMediaQuery, useOnClickOutside };
30967
31004
  //# sourceMappingURL=index.js.map
30968
31005
  //# sourceMappingURL=index.js.map