@eztrak/shared 0.16.1 → 0.16.3

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.
@@ -1577,15 +1577,49 @@ function ToolTip({
1577
1577
 
1578
1578
  // src/components/sidebar/Sidebar.tsx
1579
1579
  var import_jsx_runtime13 = require("react/jsx-runtime");
1580
+ function getItemTooltip(item) {
1581
+ return item.tooltip || item.name;
1582
+ }
1583
+ function getTooltipPlacement(item, collapsed) {
1584
+ return item.tooltipPlacement || (collapsed ? "right" : "top");
1585
+ }
1586
+ function isItemActive(pathname, link) {
1587
+ if (!link || link === "#") return false;
1588
+ return pathname === link || pathname.startsWith(`${link}/`);
1589
+ }
1590
+ function SidebarItemLabel({
1591
+ name,
1592
+ collapsed,
1593
+ className
1594
+ }) {
1595
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1596
+ "span",
1597
+ {
1598
+ className: cn(
1599
+ className,
1600
+ collapsed && "block w-full text-center text-[10px] font-medium leading-tight line-clamp-2 wrap-break-word"
1601
+ ),
1602
+ children: name
1603
+ }
1604
+ );
1605
+ }
1606
+ function SidebarItemIcon({
1607
+ icon,
1608
+ className
1609
+ }) {
1610
+ if (!icon) return null;
1611
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: cn("inline-flex shrink-0", className), "aria-hidden": "true", children: icon });
1612
+ }
1580
1613
  function Sidebar({
1581
1614
  className,
1582
- sideCollapseWidth = "w-20",
1615
+ sideCollapseWidth = "w-24",
1583
1616
  sidebarWidth = "w-48",
1584
1617
  header,
1585
1618
  children,
1586
1619
  footer,
1587
1620
  items = [],
1588
1621
  logoUrl = "",
1622
+ logoRouteUrl = "",
1589
1623
  logoAltText = "Logo",
1590
1624
  collapseButtonText = "\u2B05\uFE0F Collapse",
1591
1625
  expandButtonText = "\u27A1\uFE0F",
@@ -1598,29 +1632,68 @@ function Sidebar({
1598
1632
  }) {
1599
1633
  const location = (0, import_react_router_dom6.useLocation)();
1600
1634
  const [collapsed, setCollapsed] = (0, import_react8.useState)(isCollapsed);
1601
- const [, setActiveLink] = (0, import_react8.useState)(location.pathname);
1602
- const [subItemsCollapsed, setSubItemsCollapsed] = (0, import_react8.useState)({});
1635
+ const [openGroups, setOpenGroups] = (0, import_react8.useState)({});
1636
+ const onCollapseChangeRef = (0, import_react8.useRef)(onCollapseChange);
1637
+ onCollapseChangeRef.current = onCollapseChange;
1603
1638
  (0, import_react8.useEffect)(() => {
1604
- if (onCollapseChange) {
1605
- onCollapseChange(collapsed);
1606
- }
1607
- }, [collapsed, onCollapseChange]);
1639
+ setCollapsed(isCollapsed);
1640
+ }, [isCollapsed]);
1608
1641
  (0, import_react8.useEffect)(() => {
1609
- setActiveLink(location.pathname);
1610
- }, [location]);
1642
+ onCollapseChangeRef.current?.(collapsed);
1643
+ }, [collapsed]);
1611
1644
  const toggleGroup = (group) => {
1612
- setSubItemsCollapsed((prevState) => ({
1645
+ setOpenGroups((prevState) => ({
1613
1646
  ...prevState,
1614
1647
  [group]: !prevState[group]
1615
1648
  }));
1616
1649
  };
1617
- const isActive = (link) => {
1618
- return location.pathname.startsWith(link);
1650
+ const itemLayoutClass = (active, itemClassName) => cn(
1651
+ "flex cursor-pointer",
1652
+ classNames?.navItem,
1653
+ collapsed && "w-full flex-col items-center justify-center gap-0.5 px-1 py-2 my-1 !mx-0 max-w-full min-w-0 box-border text-center min-h-11",
1654
+ active && "active",
1655
+ itemClassName
1656
+ );
1657
+ const renderLink = (item, key) => {
1658
+ const active = isItemActive(location.pathname, item.link);
1659
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "max-w-full min-w-0", "data-sidebar-item": item.name, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1660
+ ToolTip,
1661
+ {
1662
+ text: getItemTooltip(item),
1663
+ placement: getTooltipPlacement(item, collapsed),
1664
+ delayShow: 150,
1665
+ className: "block max-w-full min-w-0",
1666
+ children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
1667
+ import_react_router_dom6.Link,
1668
+ {
1669
+ to: item.link || "#",
1670
+ className: itemLayoutClass(active, item.itemClassName),
1671
+ "aria-current": active ? "page" : void 0,
1672
+ children: [
1673
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(SidebarItemIcon, { icon: item.icon, className: classNames?.navItemText }),
1674
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1675
+ SidebarItemLabel,
1676
+ {
1677
+ name: item.name,
1678
+ collapsed,
1679
+ className: classNames?.navItemText
1680
+ }
1681
+ )
1682
+ ]
1683
+ }
1684
+ )
1685
+ }
1686
+ ) }, key);
1619
1687
  };
1620
1688
  return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
1621
1689
  "div",
1622
1690
  {
1623
- className: `flex flex-col h-screen overflow-hidden ${collapsed ? `${sideCollapseWidth} justify-center items-center collapsed` : `${sidebarWidth}`} transition-all duration-100 ${className ?? ""}`,
1691
+ className: cn(
1692
+ "flex flex-col h-screen overflow-hidden",
1693
+ collapsed ? `${sideCollapseWidth} items-stretch collapsed` : sidebarWidth,
1694
+ "transition-[width] duration-200 ease-in-out motion-reduce:transition-none",
1695
+ className
1696
+ ),
1624
1697
  ...rest,
1625
1698
  children: [
1626
1699
  logoUrl && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
@@ -1630,134 +1703,206 @@ function Sidebar({
1630
1703
  "flex items-center justify-center h-16 border-b border-gray-300",
1631
1704
  classNames.logoSection
1632
1705
  ),
1633
- children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("img", { src: logoUrl, alt: logoAltText, className: "h-10" })
1706
+ children: logoRouteUrl ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1707
+ import_react_router_dom6.Link,
1708
+ {
1709
+ to: logoRouteUrl,
1710
+ className: "sidebar-logo-link inline-flex items-center justify-center",
1711
+ children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("img", { src: logoUrl, alt: logoAltText, className: "h-10" })
1712
+ }
1713
+ ) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("img", { src: logoUrl, alt: logoAltText, className: "h-10" })
1634
1714
  }
1635
1715
  ),
1636
- header && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "flex items-center justify-between p-4 border-b border-gray-300", children: header }),
1637
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("nav", { className: cn("flex-grow", classNames.navSection), children: items.map((item, index) => {
1638
- if (item.subItems) {
1639
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
1640
- "div",
1641
- {
1642
- className: `my-2 ${item?.subItems && "has-sub-items"}`,
1643
- children: [
1644
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
1645
- "div",
1646
- {
1647
- onClick: () => toggleGroup(item.name),
1648
- "data-sidebar-item": item.name,
1649
- "data-tooltip-id": item.name,
1650
- className: `flex cursor-pointer dropdown-title-wrapper ${classNames?.navItem ?? ""}`,
1651
- children: [
1652
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1653
- ToolTip,
1654
- {
1655
- text: item.tooltip || item.name,
1656
- placement: item.tooltipPlacement || "top",
1657
- children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center space-x-2", children: [
1658
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: classNames?.navItemText, children: item.icon }),
1659
- !collapsed && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: classNames?.navItemText, children: item.name })
1660
- ] })
1661
- }
1662
- ),
1663
- !collapsed && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1664
- "span",
1665
- {
1666
- className: `transform transition-transform ${subItemsCollapsed[item.name] ? "rotate-180" : "rotate-0"}`,
1667
- children: itemDropdownIcon
1668
- }
1669
- )
1670
- ]
1671
- }
1672
- ),
1673
- subItemsCollapsed[item.name] && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: cn("collapse-btn-wrapper", classNames.subItem), children: item.subItems.map((subItem, subIndex) => {
1674
- if (subItem.component) {
1675
- const SubItemComponent = subItem.component;
1676
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(SubItemComponent, {}, `${index}-${subIndex}`);
1677
- }
1678
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1679
- "div",
1680
- {
1681
- className: "w-full",
1682
- "data-sidebar-item": subItem.name,
1683
- "data-tooltip-id": subItem.name,
1684
- children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1685
- ToolTip,
1686
- {
1687
- text: item.tooltip || item.name,
1688
- placement: item.tooltipPlacement || "top",
1689
- className: "block w-full",
1690
- children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
1691
- import_react_router_dom6.Link,
1692
- {
1693
- to: subItem.link || "#",
1694
- className: `flex ${classNames?.navItem ?? ""} ${isActive(subItem?.link ?? "") ? "active" : ""} ${item?.itemClassName}`,
1695
- onClick: () => subItem.link && setActiveLink(subItem.link || ""),
1696
- title: subItem.tooltip || subItem.name,
1697
- children: [
1698
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1699
- "span",
1700
- {
1701
- className: classNames.navItemText ?? "text-orange-600",
1702
- children: subItem.icon
1703
- }
1716
+ header && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "flex items-center justify-between p-4 border-b border-gray-300 shrink-0", children: header }),
1717
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1718
+ "nav",
1719
+ {
1720
+ "aria-label": "Sidebar",
1721
+ className: cn(
1722
+ "grow min-h-0 min-w-0 w-full",
1723
+ classNames.navSection
1724
+ ),
1725
+ children: items.map((item, index) => {
1726
+ if (item.subItems) {
1727
+ const groupOpen = Boolean(openGroups[item.name]);
1728
+ const groupId = `sidebar-group-${index}`;
1729
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
1730
+ "div",
1731
+ {
1732
+ "data-sidebar-item": item.name,
1733
+ className: cn(
1734
+ "has-sub-items max-w-full min-w-0 flex flex-col",
1735
+ collapsed ? "my-1" : "my-2"
1736
+ ),
1737
+ children: [
1738
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1739
+ ToolTip,
1740
+ {
1741
+ text: getItemTooltip(item),
1742
+ placement: getTooltipPlacement(item, collapsed),
1743
+ delayShow: 150,
1744
+ className: "flex flex-col w-full max-w-full min-w-0",
1745
+ children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
1746
+ "button",
1747
+ {
1748
+ type: "button",
1749
+ onClick: () => toggleGroup(item.name),
1750
+ "data-sidebar-item": item.name,
1751
+ "aria-expanded": groupOpen,
1752
+ "aria-controls": groupId,
1753
+ className: cn(
1754
+ itemLayoutClass(false, item.itemClassName),
1755
+ !collapsed && "dropdown-title-wrapper",
1756
+ "relative appearance-none border-0 bg-transparent [font:inherit]"
1757
+ ),
1758
+ children: [
1759
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
1760
+ "span",
1761
+ {
1762
+ className: cn(
1763
+ "flex items-center min-w-0",
1764
+ collapsed ? "flex-col gap-0.5 w-full" : "space-x-2 flex-1"
1765
+ ),
1766
+ children: [
1767
+ collapsed ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "flex w-full items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "inline-flex items-center gap-2", children: [
1768
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "inline-flex w-3 shrink-0", "aria-hidden": "true" }),
1769
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1770
+ SidebarItemIcon,
1771
+ {
1772
+ icon: item.icon,
1773
+ className: classNames?.navItemText
1774
+ }
1775
+ ),
1776
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1777
+ "span",
1778
+ {
1779
+ className: cn(
1780
+ "sidebar-group-caret inline-flex w-3 shrink-0 items-center justify-center text-current [&>svg]:h-3 [&>svg]:w-3 transition-transform duration-200 motion-reduce:transition-none",
1781
+ groupOpen ? "rotate-180" : "rotate-0"
1782
+ ),
1783
+ "aria-hidden": "true",
1784
+ children: itemDropdownIcon
1785
+ }
1786
+ )
1787
+ ] }) }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "flex items-center space-x-2 min-w-0 flex-1", children: [
1788
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1789
+ SidebarItemIcon,
1790
+ {
1791
+ icon: item.icon,
1792
+ className: classNames?.navItemText
1793
+ }
1794
+ ),
1795
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1796
+ SidebarItemLabel,
1797
+ {
1798
+ name: item.name,
1799
+ collapsed: false,
1800
+ className: classNames?.navItemText
1801
+ }
1802
+ )
1803
+ ] }),
1804
+ collapsed && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1805
+ SidebarItemLabel,
1806
+ {
1807
+ name: item.name,
1808
+ collapsed: true,
1809
+ className: classNames?.navItemText
1810
+ }
1811
+ )
1812
+ ]
1813
+ }
1814
+ ),
1815
+ !collapsed && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1816
+ "span",
1817
+ {
1818
+ className: cn(
1819
+ "transform transition-transform duration-200 motion-reduce:transition-none",
1820
+ groupOpen ? "rotate-180" : "rotate-0"
1821
+ ),
1822
+ "aria-hidden": "true",
1823
+ children: itemDropdownIcon
1824
+ }
1825
+ )
1826
+ ]
1827
+ }
1828
+ )
1829
+ }
1830
+ ),
1831
+ groupOpen && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1832
+ "div",
1833
+ {
1834
+ id: groupId,
1835
+ role: "group",
1836
+ "aria-label": item.name,
1837
+ className: cn(
1838
+ collapsed ? "sidebar-sub-panel flex flex-col items-center max-w-full min-w-0 box-border" : "collapse-btn-wrapper",
1839
+ classNames.subItem
1840
+ ),
1841
+ children: item.subItems.map((subItem, subIndex) => {
1842
+ if (subItem.component) {
1843
+ const SubItemComponent = subItem.component;
1844
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
1845
+ "div",
1846
+ {
1847
+ className: cn(
1848
+ "min-w-0 max-w-full",
1849
+ collapsed && "flex flex-col items-center text-center"
1704
1850
  ),
1705
- !collapsed && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: classNames.navItemText, children: subItem.name })
1706
- ]
1707
- }
1708
- )
1709
- }
1710
- )
1711
- },
1712
- `${index}-${subIndex}`
1713
- );
1714
- }) })
1715
- ]
1716
- },
1717
- index
1718
- );
1851
+ "data-sidebar-item": subItem.name,
1852
+ children: [
1853
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(SubItemComponent, {}),
1854
+ collapsed && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1855
+ SidebarItemLabel,
1856
+ {
1857
+ name: subItem.name,
1858
+ collapsed: true,
1859
+ className: classNames?.navItemText
1860
+ }
1861
+ )
1862
+ ]
1863
+ },
1864
+ `${index}-${subIndex}`
1865
+ );
1866
+ }
1867
+ return renderLink(subItem, `${index}-${subIndex}`);
1868
+ })
1869
+ }
1870
+ )
1871
+ ]
1872
+ },
1873
+ index
1874
+ );
1875
+ }
1876
+ if (item.component) {
1877
+ const ItemComponent = item.component;
1878
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ItemComponent, {}, index);
1879
+ }
1880
+ return renderLink(item, String(index));
1881
+ })
1719
1882
  }
1720
- if (item.component) {
1721
- const ItemComponent = item.component;
1722
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ItemComponent, {}, index);
1883
+ ),
1884
+ children != null && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1885
+ "div",
1886
+ {
1887
+ className: cn(
1888
+ "sidebar-chrome w-full shrink-0",
1889
+ collapsed && "flex flex-col items-center"
1890
+ ),
1891
+ children
1723
1892
  }
1724
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1725
- "div",
1726
- {
1727
- className: "w-full",
1728
- "data-sidebar-item": item.name,
1729
- "data-tooltip-id": item.name,
1730
- children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1731
- ToolTip,
1732
- {
1733
- text: item.tooltip || item.name,
1734
- placement: item.tooltipPlacement || "top",
1735
- className: "block w-full",
1736
- children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
1737
- import_react_router_dom6.Link,
1738
- {
1739
- to: item.link || "#",
1740
- className: `flex ${classNames?.navItem ?? ""} ${isActive(item.link || "") ? "active" : ""} ${item?.itemClassName}`,
1741
- onClick: () => setActiveLink(item.link || ""),
1742
- title: item.tooltip || item.name,
1743
- children: [
1744
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: classNames.navItemText ?? "text-orange-600", children: item.icon }),
1745
- !collapsed && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: classNames.navItemText, children: item.name })
1746
- ]
1747
- }
1748
- )
1749
- }
1750
- )
1751
- },
1752
- index
1753
- );
1754
- }) }),
1755
- children,
1893
+ ),
1756
1894
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1757
1895
  "button",
1758
1896
  {
1897
+ type: "button",
1759
1898
  onClick: () => setCollapsed(!collapsed),
1760
- className: cn("", classNames.collapseButton) ?? "p-4 border-t border-gray-300",
1899
+ "aria-expanded": !collapsed,
1900
+ "aria-label": collapsed ? "Expand sidebar" : "Collapse sidebar",
1901
+ className: cn(
1902
+ "shrink-0 border-t border-gray-300",
1903
+ classNames.collapseButton,
1904
+ collapsed && "flex items-center justify-center"
1905
+ ),
1761
1906
  children: collapsed ? expandButtonText : collapseButtonText
1762
1907
  }
1763
1908
  ),