@eztrak/shared 0.13.8 → 0.15.0

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.
@@ -4,10 +4,11 @@ import {
4
4
  confirmationAlert,
5
5
  getItemFromLocalStorage,
6
6
  removeItem,
7
+ resetPageParam,
7
8
  storeItemInLocalStorage,
8
9
  toDateInputValue,
9
10
  truncateText
10
- } from "./chunk-DSP67UYZ.mjs";
11
+ } from "./chunk-EIX5CUQF.mjs";
11
12
 
12
13
  // src/components/tabs/EztrakTabs.tsx
13
14
  import {
@@ -624,6 +625,7 @@ function DropdownFilter({
624
625
  isDisabled = false,
625
626
  isLoading = false,
626
627
  saveToLocalStorage = false,
628
+ pageParam = "page",
627
629
  ...otherProps
628
630
  }) {
629
631
  const [searchParams, setSearchParams] = useSearchParams2();
@@ -636,10 +638,10 @@ function DropdownFilter({
636
638
  if (stored != null && stored !== "") {
637
639
  setSearchParams((prev) => {
638
640
  prev.set(name, String(stored));
639
- return prev;
641
+ return resetPageParam(prev, pageParam);
640
642
  });
641
643
  }
642
- }, [saveToLocalStorage, name, searchParams, setSearchParams]);
644
+ }, [saveToLocalStorage, name, pageParam, searchParams, setSearchParams]);
643
645
  const currentValue = searchParams.get(name);
644
646
  const selectedOption = currentValue ? options?.find(
645
647
  (option) => option[valueKey]?.toString() === currentValue
@@ -647,12 +649,15 @@ function DropdownFilter({
647
649
  const handleChange = (selected) => {
648
650
  const selectedValue = selected && selected[valueKey] !== "" ? String(selected[valueKey]) : null;
649
651
  setSearchParams((prev) => {
652
+ if ((prev.get(name) ?? "") === (selectedValue ?? "")) {
653
+ return prev;
654
+ }
650
655
  if (!selectedValue) {
651
656
  prev.delete(name);
652
657
  } else {
653
658
  prev.set(name, selectedValue);
654
659
  }
655
- return prev;
660
+ return resetPageParam(prev, pageParam);
656
661
  });
657
662
  if (saveToLocalStorage) {
658
663
  if (selectedValue) {
@@ -773,6 +778,7 @@ function SearchInput({
773
778
  debounceDelay = 500,
774
779
  customIcon = null,
775
780
  defaultValue,
781
+ pageParam = "page",
776
782
  ...props
777
783
  }) {
778
784
  const [searchParams, setSearchParams] = useSearchParams4();
@@ -780,17 +786,18 @@ function SearchInput({
780
786
  const [inputValue, setInputValue] = useState2(queryParam);
781
787
  const debounceTimerRef = useRef3(null);
782
788
  const updateSearchParams = (searchQuery) => {
783
- if (searchQuery?.trim()) {
784
- setSearchParams((prev) => {
785
- prev.set(defaultParam, searchQuery.trim());
789
+ const nextValue = searchQuery?.trim() ?? "";
790
+ setSearchParams((prev) => {
791
+ if ((prev.get(defaultParam) ?? "") === nextValue) {
786
792
  return prev;
787
- });
788
- } else {
789
- setSearchParams((prev) => {
793
+ }
794
+ if (nextValue) {
795
+ prev.set(defaultParam, nextValue);
796
+ } else {
790
797
  prev.delete(defaultParam);
791
- return prev;
792
- });
793
- }
798
+ }
799
+ return resetPageParam(prev, pageParam);
800
+ });
794
801
  };
795
802
  const handleSearch = (e) => {
796
803
  e.preventDefault();
@@ -1515,7 +1522,8 @@ function PopupCellRenderer({
1515
1522
  params,
1516
1523
  onAction,
1517
1524
  placement = "bottom-end",
1518
- tippyProps
1525
+ tippyProps,
1526
+ ariaLabel = "Row actions"
1519
1527
  }) {
1520
1528
  const [visible, setVisible] = useState4(false);
1521
1529
  const show = () => setVisible(true);
@@ -1551,7 +1559,7 @@ function PopupCellRenderer({
1551
1559
  "flex items-center justify-center gap-2 rounded-full text-gray-500 hover:text-gray-800",
1552
1560
  className
1553
1561
  ),
1554
- "aria-label": "Row actions",
1562
+ "aria-label": ariaLabel,
1555
1563
  children: [
1556
1564
  !hideTitle && title,
1557
1565
  /* @__PURE__ */ jsx12(ActionIcon, { "aria-hidden": true })
@@ -1562,10 +1570,305 @@ function PopupCellRenderer({
1562
1570
  ) });
1563
1571
  }
1564
1572
 
1573
+ // src/components/row-actions/presets.ts
1574
+ import {
1575
+ FaArchive,
1576
+ FaCheckCircle,
1577
+ FaDownload,
1578
+ FaEdit,
1579
+ FaEye,
1580
+ FaFileAlt,
1581
+ FaHistory,
1582
+ FaTrashAlt
1583
+ } from "react-icons/fa";
1584
+ var ROW_ACTION_ITEM_HOVER_CLASS = "hover:bg-primary-50 hover:text-primary-150";
1585
+ var ROW_ACTION_DEFAULT_ICON_SIZE = 16;
1586
+ var ROW_ACTION_DEFAULT_MENU_TOOLTIP_STYLE = {
1587
+ zIndex: 1e4
1588
+ };
1589
+ var ROW_ACTION_PRESETS = {
1590
+ edit: { label: "Edit", icon: FaEdit },
1591
+ delete: { label: "Delete", icon: FaTrashAlt, danger: true },
1592
+ view: { label: "View", icon: FaEye },
1593
+ notes: { label: "Notes", icon: FaFileAlt },
1594
+ history: { label: "History", icon: FaHistory },
1595
+ download: { label: "Download", icon: FaDownload },
1596
+ archive: { label: "Archive", icon: FaArchive },
1597
+ resolve: { label: "Resolve", icon: FaCheckCircle }
1598
+ };
1599
+
1600
+ // src/components/row-actions/ActionMenuItem.tsx
1601
+ import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
1602
+ function ActionMenuItem({
1603
+ label,
1604
+ icon: Icon,
1605
+ iconSize = ROW_ACTION_DEFAULT_ICON_SIZE,
1606
+ iconClassName,
1607
+ tooltip,
1608
+ tooltipPlacement = "top",
1609
+ tooltipDelayShow,
1610
+ tooltipDelayHide,
1611
+ tooltipClassName,
1612
+ tooltipStyle,
1613
+ disabled = false,
1614
+ danger = false,
1615
+ highlight = false,
1616
+ showLabel = true,
1617
+ className,
1618
+ onClick
1619
+ }) {
1620
+ const tooltipText = tooltip ?? label;
1621
+ return /* @__PURE__ */ jsx13(
1622
+ ToolTip,
1623
+ {
1624
+ text: tooltipText,
1625
+ disabled: !tooltipText,
1626
+ placement: tooltipPlacement,
1627
+ delayShow: tooltipDelayShow,
1628
+ delayHide: tooltipDelayHide,
1629
+ tooltipClassName,
1630
+ tooltipStyle: { ...ROW_ACTION_DEFAULT_MENU_TOOLTIP_STYLE, ...tooltipStyle },
1631
+ className: showLabel ? "block w-full" : "inline-flex",
1632
+ children: /* @__PURE__ */ jsxs10(
1633
+ "button",
1634
+ {
1635
+ type: "button",
1636
+ disabled,
1637
+ "aria-label": label,
1638
+ onClick: (event) => {
1639
+ event.stopPropagation();
1640
+ if (disabled) return;
1641
+ onClick();
1642
+ },
1643
+ className: cn(
1644
+ "flex items-center gap-2 text-sm transition-colors duration-150",
1645
+ showLabel ? "w-full rounded-xl px-3 py-2 text-left" : "justify-center rounded-md p-1",
1646
+ disabled ? "cursor-not-allowed opacity-50" : ROW_ACTION_ITEM_HOVER_CLASS,
1647
+ danger && "text-red-500",
1648
+ highlight && !danger && "text-primary-150",
1649
+ className
1650
+ ),
1651
+ children: [
1652
+ Icon ? /* @__PURE__ */ jsx13(
1653
+ Icon,
1654
+ {
1655
+ className: cn("shrink-0", iconClassName),
1656
+ "aria-hidden": true,
1657
+ size: iconSize
1658
+ }
1659
+ ) : null,
1660
+ showLabel ? /* @__PURE__ */ jsx13("span", { children: label }) : null
1661
+ ]
1662
+ }
1663
+ )
1664
+ }
1665
+ );
1666
+ }
1667
+
1668
+ // src/components/row-actions/resolveActions.ts
1669
+ function evalFlag(flag, data) {
1670
+ if (typeof flag === "function") return Boolean(flag(data));
1671
+ return Boolean(flag);
1672
+ }
1673
+ function mergePreset(name, overrides) {
1674
+ if (!name) return void 0;
1675
+ const base = ROW_ACTION_PRESETS[name];
1676
+ const extra = overrides?.[name];
1677
+ if (!extra) return base;
1678
+ return { ...base, ...extra };
1679
+ }
1680
+ function resolveActions(actions, data, hasPermission, presets) {
1681
+ const list = typeof actions === "function" ? actions(data) : actions;
1682
+ return list.flatMap((action, index) => {
1683
+ const type = action.type ?? "item";
1684
+ const preset = mergePreset(action.preset, presets);
1685
+ const key = action.key ?? action.preset ?? `action-${index}`;
1686
+ const label = action.label ?? preset?.label ?? key;
1687
+ if (action.permission && hasPermission && !hasPermission(action.permission)) {
1688
+ return [];
1689
+ }
1690
+ if (evalFlag(action.hidden, data)) {
1691
+ return [];
1692
+ }
1693
+ const tooltip = action.tooltip === false ? void 0 : action.tooltip ?? (type === "divider" ? void 0 : label);
1694
+ const resolved = {
1695
+ key,
1696
+ type,
1697
+ label,
1698
+ icon: action.icon ?? preset?.icon,
1699
+ iconSize: action.iconSize,
1700
+ content: action.content,
1701
+ onClick: action.onClick,
1702
+ disabled: evalFlag(action.disabled, data),
1703
+ danger: action.danger ?? preset?.danger ?? false,
1704
+ highlight: evalFlag(action.highlight, data),
1705
+ tooltip,
1706
+ tooltipPlacement: action.tooltipPlacement,
1707
+ confirm: action.confirm,
1708
+ closeOnClick: action.closeOnClick !== false,
1709
+ className: action.className
1710
+ };
1711
+ return [resolved];
1712
+ });
1713
+ }
1714
+
1715
+ // src/components/row-actions/RowActions.tsx
1716
+ import { Fragment as Fragment3, jsx as jsx14 } from "react/jsx-runtime";
1717
+ function runAction(action, data, hide, confirmFn = confirmationAlert) {
1718
+ if (!action.onClick) {
1719
+ if (action.closeOnClick) hide?.();
1720
+ return;
1721
+ }
1722
+ const execute = () => action.onClick?.(data);
1723
+ if (action.confirm) {
1724
+ confirmFn?.(execute, action.confirm);
1725
+ } else {
1726
+ execute();
1727
+ }
1728
+ if (action.closeOnClick) {
1729
+ hide?.();
1730
+ }
1731
+ }
1732
+ function RowActions({
1733
+ actions,
1734
+ data,
1735
+ mode = "menu",
1736
+ actionIcon,
1737
+ className,
1738
+ menuClassName,
1739
+ itemClassName,
1740
+ itemIconClassName,
1741
+ iconSize = ROW_ACTION_DEFAULT_ICON_SIZE,
1742
+ triggerTooltip = "Actions",
1743
+ triggerAriaLabel = "Row actions",
1744
+ hasPermission,
1745
+ placement = "bottom-end",
1746
+ tippyProps,
1747
+ presets,
1748
+ confirmFn = confirmationAlert,
1749
+ tooltipPlacement = "top",
1750
+ tooltipDelayShow,
1751
+ tooltipDelayHide,
1752
+ tooltipClassName,
1753
+ tooltipStyle,
1754
+ renderItem,
1755
+ renderMenu,
1756
+ renderTrigger
1757
+ }) {
1758
+ const resolved = resolveActions(actions, data, hasPermission, presets);
1759
+ if (resolved.length === 0) {
1760
+ return null;
1761
+ }
1762
+ const mergedTooltipStyle = {
1763
+ ...ROW_ACTION_DEFAULT_MENU_TOOLTIP_STYLE,
1764
+ ...tooltipStyle
1765
+ };
1766
+ const renderDefaultItem = (action, hide, showLabel = true) => {
1767
+ if (action.type === "divider") {
1768
+ return /* @__PURE__ */ jsx14(
1769
+ "div",
1770
+ {
1771
+ role: "separator",
1772
+ className: cn("my-1 h-px bg-gray-100", action.className)
1773
+ },
1774
+ action.key
1775
+ );
1776
+ }
1777
+ if (action.content) {
1778
+ return /* @__PURE__ */ jsx14("div", { className: action.className, children: action.content }, action.key);
1779
+ }
1780
+ return /* @__PURE__ */ jsx14(
1781
+ ActionMenuItem,
1782
+ {
1783
+ label: action.label,
1784
+ icon: action.icon,
1785
+ iconSize: action.iconSize ?? iconSize,
1786
+ iconClassName: itemIconClassName,
1787
+ tooltip: action.tooltip,
1788
+ tooltipPlacement: action.tooltipPlacement ?? tooltipPlacement,
1789
+ tooltipDelayShow,
1790
+ tooltipDelayHide,
1791
+ tooltipClassName,
1792
+ tooltipStyle: mergedTooltipStyle,
1793
+ disabled: action.disabled,
1794
+ danger: action.danger,
1795
+ highlight: action.highlight,
1796
+ showLabel,
1797
+ className: cn(itemClassName, action.className),
1798
+ onClick: () => runAction(action, data, hide, confirmFn)
1799
+ },
1800
+ action.key
1801
+ );
1802
+ };
1803
+ const renderItems = (hide, showLabel = true) => resolved.map((action) => {
1804
+ const defaultItem = renderDefaultItem(action, hide, showLabel);
1805
+ if (!renderItem) return defaultItem;
1806
+ return /* @__PURE__ */ jsx14("div", { children: renderItem(action, { data, hide: hide ?? (() => void 0), defaultItem }) }, action.key);
1807
+ });
1808
+ if (mode === "inline") {
1809
+ const inlineItems = renderItems(void 0, false);
1810
+ return /* @__PURE__ */ jsx14("div", { className: cn("flex h-full items-center justify-center gap-1", className), children: inlineItems });
1811
+ }
1812
+ const triggerTooltipText = triggerTooltip === false ? void 0 : triggerTooltip;
1813
+ const buildMenu = (hide) => {
1814
+ const defaultMenu = /* @__PURE__ */ jsx14(
1815
+ "div",
1816
+ {
1817
+ className: cn(
1818
+ "flex min-w-[180px] flex-col rounded-lg border border-gray-100 bg-white p-2 shadow-lg",
1819
+ menuClassName
1820
+ ),
1821
+ children: renderItems(hide, true)
1822
+ }
1823
+ );
1824
+ if (!renderMenu) return defaultMenu;
1825
+ return renderMenu({
1826
+ data,
1827
+ actions: resolved,
1828
+ hide,
1829
+ defaultMenu
1830
+ });
1831
+ };
1832
+ if (renderTrigger) {
1833
+ return /* @__PURE__ */ jsx14(Fragment3, { children: renderTrigger({
1834
+ data,
1835
+ actions: resolved,
1836
+ hide: () => void 0,
1837
+ defaultMenu: buildMenu(() => void 0)
1838
+ }) });
1839
+ }
1840
+ return /* @__PURE__ */ jsx14(
1841
+ ToolTip,
1842
+ {
1843
+ text: triggerTooltipText,
1844
+ disabled: !triggerTooltipText,
1845
+ placement: tooltipPlacement,
1846
+ delayShow: tooltipDelayShow,
1847
+ delayHide: tooltipDelayHide,
1848
+ tooltipClassName,
1849
+ tooltipStyle,
1850
+ className: "flex h-full items-center justify-center",
1851
+ children: /* @__PURE__ */ jsx14(
1852
+ PopupCellRenderer,
1853
+ {
1854
+ params: { data },
1855
+ actionIcon,
1856
+ hideTitle: true,
1857
+ className,
1858
+ placement,
1859
+ tippyProps,
1860
+ ariaLabel: triggerAriaLabel,
1861
+ dropDownContent: (handleAction) => buildMenu(() => handleAction("close"))
1862
+ }
1863
+ )
1864
+ }
1865
+ );
1866
+ }
1867
+
1565
1868
  // src/components/table-error-boundary/TableErrorBoundary.tsx
1566
1869
  import { useMemo as useMemo2 } from "react";
1567
1870
  import { FaArrowsRotate, FaTriangleExclamation } from "react-icons/fa6";
1568
- import { Fragment as Fragment3, jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
1871
+ import { Fragment as Fragment4, jsx as jsx15, jsxs as jsxs11 } from "react/jsx-runtime";
1569
1872
  var TableErrorBoundary = ({
1570
1873
  isError,
1571
1874
  isLoading = false,
@@ -1582,7 +1885,7 @@ var TableErrorBoundary = ({
1582
1885
  return "Unable to load table data. Please try again.";
1583
1886
  }, [error, errorMessage]);
1584
1887
  if (isLoading && !isError) {
1585
- return /* @__PURE__ */ jsx13(
1888
+ return /* @__PURE__ */ jsx15(
1586
1889
  "div",
1587
1890
  {
1588
1891
  className: cn(
@@ -1593,12 +1896,12 @@ var TableErrorBoundary = ({
1593
1896
  role: "status",
1594
1897
  "aria-live": "polite",
1595
1898
  "aria-busy": "true",
1596
- children: /* @__PURE__ */ jsx13(Loader, { size: "40px" })
1899
+ children: /* @__PURE__ */ jsx15(Loader, { size: "40px" })
1597
1900
  }
1598
1901
  );
1599
1902
  }
1600
1903
  if (isError) {
1601
- return /* @__PURE__ */ jsxs10(
1904
+ return /* @__PURE__ */ jsxs11(
1602
1905
  "div",
1603
1906
  {
1604
1907
  className: cn(
@@ -1609,7 +1912,7 @@ var TableErrorBoundary = ({
1609
1912
  role: "alert",
1610
1913
  "aria-live": "assertive",
1611
1914
  children: [
1612
- /* @__PURE__ */ jsx13(
1915
+ /* @__PURE__ */ jsx15(
1613
1916
  FaTriangleExclamation,
1614
1917
  {
1615
1918
  className: "text-red-500",
@@ -1617,11 +1920,11 @@ var TableErrorBoundary = ({
1617
1920
  "aria-hidden": true
1618
1921
  }
1619
1922
  ),
1620
- /* @__PURE__ */ jsxs10("div", { className: "max-w-md space-y-1", children: [
1621
- /* @__PURE__ */ jsx13("p", { className: "text-base font-semibold text-gray-800", children: "Failed to load data" }),
1622
- /* @__PURE__ */ jsx13("p", { className: "text-sm text-gray-600", children: message })
1923
+ /* @__PURE__ */ jsxs11("div", { className: "max-w-md space-y-1", children: [
1924
+ /* @__PURE__ */ jsx15("p", { className: "text-base font-semibold text-gray-800", children: "Failed to load data" }),
1925
+ /* @__PURE__ */ jsx15("p", { className: "text-sm text-gray-600", children: message })
1623
1926
  ] }),
1624
- refetch && /* @__PURE__ */ jsxs10(
1927
+ refetch && /* @__PURE__ */ jsxs11(
1625
1928
  "button",
1626
1929
  {
1627
1930
  type: "button",
@@ -1629,7 +1932,7 @@ var TableErrorBoundary = ({
1629
1932
  disabled: isLoading,
1630
1933
  className: "inline-flex items-center gap-2 rounded-lg bg-primary-150 px-4 py-2 text-sm font-medium text-white transition-colors hover:opacity-90 disabled:cursor-not-allowed disabled:opacity-60",
1631
1934
  children: [
1632
- /* @__PURE__ */ jsx13(FaArrowsRotate, { className: cn(isLoading && "animate-spin") }),
1935
+ /* @__PURE__ */ jsx15(FaArrowsRotate, { className: cn(isLoading && "animate-spin") }),
1633
1936
  isLoading ? "Retrying..." : "Try again"
1634
1937
  ]
1635
1938
  }
@@ -1638,7 +1941,7 @@ var TableErrorBoundary = ({
1638
1941
  }
1639
1942
  );
1640
1943
  }
1641
- return /* @__PURE__ */ jsx13(Fragment3, { children });
1944
+ return /* @__PURE__ */ jsx15(Fragment4, { children });
1642
1945
  };
1643
1946
 
1644
1947
  export {
@@ -1657,6 +1960,13 @@ export {
1657
1960
  TooltipText,
1658
1961
  CustomCellEditor,
1659
1962
  PopupCellRenderer,
1963
+ ROW_ACTION_ITEM_HOVER_CLASS,
1964
+ ROW_ACTION_DEFAULT_ICON_SIZE,
1965
+ ROW_ACTION_DEFAULT_MENU_TOOLTIP_STYLE,
1966
+ ROW_ACTION_PRESETS,
1967
+ ActionMenuItem,
1968
+ resolveActions,
1969
+ RowActions,
1660
1970
  TableErrorBoundary
1661
1971
  };
1662
- //# sourceMappingURL=chunk-4SOWLOGR.mjs.map
1972
+ //# sourceMappingURL=chunk-KFBKDGZV.mjs.map