@eztrak/shared 0.4.9 → 0.6.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.
- package/README.md +26 -1
- package/dist/{chunk-LDEHCACA.mjs → chunk-BI64GTKG.mjs} +208 -2
- package/dist/chunk-BI64GTKG.mjs.map +1 -0
- package/dist/components/index.d.mts +34 -1
- package/dist/components/index.d.ts +34 -1
- package/dist/components/index.js +208 -0
- package/dist/components/index.js.map +1 -1
- package/dist/components/index.mjs +5 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +208 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +5 -1
- package/package.json +6 -1
- package/dist/chunk-LDEHCACA.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -171,6 +171,31 @@ import {
|
|
|
171
171
|
|
|
172
172
|
`ResetColumnsButton` shows a SweetAlert2 confirmation before calling `onReset`.
|
|
173
173
|
|
|
174
|
+
### Components — ResetFiltersButton
|
|
175
|
+
|
|
176
|
+
Clears all URL search params (`react-router-dom`) in one click. Self-contained — no app `Button` needed.
|
|
177
|
+
|
|
178
|
+
```tsx
|
|
179
|
+
import { ResetFiltersButton } from "@eztrak/shared/components";
|
|
180
|
+
|
|
181
|
+
// Default look + reset icon
|
|
182
|
+
<ResetFiltersButton />
|
|
183
|
+
|
|
184
|
+
// Custom label and an extra callback after reset
|
|
185
|
+
<ResetFiltersButton label="Clear" onReset={() => refetch()} />
|
|
186
|
+
|
|
187
|
+
// Override styles (e.g. solid red) and hide the icon
|
|
188
|
+
<ResetFiltersButton icon={null} className="bg-red-500 text-white border-0" />
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
| Prop | Type | Default | Description |
|
|
192
|
+
| --- | --- | --- | --- |
|
|
193
|
+
| `label` | `string` | `"Reset Filters"` | Button text |
|
|
194
|
+
| `icon` | `ReactNode` | reset icon | Leading icon; pass `null` to hide |
|
|
195
|
+
| `className` | `string` | — | Classes merged with the default styles |
|
|
196
|
+
| `onReset` | `() => void` | — | Called after search params are cleared |
|
|
197
|
+
| `disabled` | `boolean` | `false` | Disables the button |
|
|
198
|
+
|
|
174
199
|
### Components — EztrakTabs
|
|
175
200
|
|
|
176
201
|
Import styles once in your app entry or layout:
|
|
@@ -312,7 +337,7 @@ Opens on [http://localhost:6006](http://localhost:6006) with stories for `Eztrak
|
|
|
312
337
|
| `@eztrak/shared` | Main entry — re-exports utils, hooks, and components |
|
|
313
338
|
| `@eztrak/shared/utils` | `cn`, `handleApiError`, `confirmationAlert`, date/format helpers, API error helpers, form field helpers |
|
|
314
339
|
| `@eztrak/shared/hooks` | `usePaginationUrlSync`, `useGridHeight` |
|
|
315
|
-
| `@eztrak/shared/components` | `EztrakTabs`, `CustomPagination`, `ResetColumnsButton`, `TableLayoutToolbarControls`, and related types |
|
|
340
|
+
| `@eztrak/shared/components` | `EztrakTabs`, `CustomPagination`, `ResetColumnsButton`, `TableLayoutToolbarControls`, `ResetFiltersButton`, and related types |
|
|
316
341
|
| `@eztrak/shared/components/tabs.css` | Default tab styles (CSS variables) |
|
|
317
342
|
|
|
318
343
|
### EztrakTabs props
|
|
@@ -531,10 +531,216 @@ function CustomPagination({
|
|
|
531
531
|
);
|
|
532
532
|
}
|
|
533
533
|
|
|
534
|
+
// src/components/search-filters/ResetFiltersButton.tsx
|
|
535
|
+
import { useSearchParams as useSearchParams2 } from "react-router-dom";
|
|
536
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
537
|
+
function ResetIcon({
|
|
538
|
+
size = 16,
|
|
539
|
+
className
|
|
540
|
+
}) {
|
|
541
|
+
return /* @__PURE__ */ jsxs3(
|
|
542
|
+
"svg",
|
|
543
|
+
{
|
|
544
|
+
width: size,
|
|
545
|
+
height: size,
|
|
546
|
+
viewBox: "0 0 24 24",
|
|
547
|
+
fill: "none",
|
|
548
|
+
stroke: "currentColor",
|
|
549
|
+
strokeWidth: "2",
|
|
550
|
+
strokeLinecap: "round",
|
|
551
|
+
strokeLinejoin: "round",
|
|
552
|
+
"aria-hidden": "true",
|
|
553
|
+
className,
|
|
554
|
+
children: [
|
|
555
|
+
/* @__PURE__ */ jsx3("path", { d: "M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8" }),
|
|
556
|
+
/* @__PURE__ */ jsx3("path", { d: "M21 3v5h-5" }),
|
|
557
|
+
/* @__PURE__ */ jsx3("path", { d: "M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16" }),
|
|
558
|
+
/* @__PURE__ */ jsx3("path", { d: "M8 16H3v5" })
|
|
559
|
+
]
|
|
560
|
+
}
|
|
561
|
+
);
|
|
562
|
+
}
|
|
563
|
+
function ResetFiltersButton({
|
|
564
|
+
label = "Reset Filters",
|
|
565
|
+
icon,
|
|
566
|
+
className,
|
|
567
|
+
onReset,
|
|
568
|
+
disabled = false
|
|
569
|
+
}) {
|
|
570
|
+
const [, setSearchParams] = useSearchParams2();
|
|
571
|
+
const handleReset = () => {
|
|
572
|
+
setSearchParams({}, { replace: true });
|
|
573
|
+
onReset?.();
|
|
574
|
+
};
|
|
575
|
+
const resolvedIcon = icon === void 0 ? /* @__PURE__ */ jsx3(ResetIcon, { size: 16 }) : icon;
|
|
576
|
+
return /* @__PURE__ */ jsxs3(
|
|
577
|
+
"button",
|
|
578
|
+
{
|
|
579
|
+
type: "button",
|
|
580
|
+
onClick: handleReset,
|
|
581
|
+
disabled,
|
|
582
|
+
className: cn(
|
|
583
|
+
"inline-flex items-center gap-1.5 rounded-xl border border-primary-150 bg-white px-3 py-1.5 text-sm font-medium text-primary-150 hover:bg-gray-50 focus:outline-none disabled:cursor-not-allowed disabled:opacity-50 disabled:hover:bg-white",
|
|
584
|
+
className
|
|
585
|
+
),
|
|
586
|
+
children: [
|
|
587
|
+
resolvedIcon,
|
|
588
|
+
label
|
|
589
|
+
]
|
|
590
|
+
}
|
|
591
|
+
);
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
// src/components/modal/Modal.tsx
|
|
595
|
+
import { AnimatePresence, motion } from "framer-motion";
|
|
596
|
+
import { useEffect as useEffect2, useRef as useRef2 } from "react";
|
|
597
|
+
import { createPortal } from "react-dom";
|
|
598
|
+
import { FaFileExport, FaPrint } from "react-icons/fa";
|
|
599
|
+
import { IoCloseCircleOutline } from "react-icons/io5";
|
|
600
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
601
|
+
function Modal({
|
|
602
|
+
isOpen,
|
|
603
|
+
onClose,
|
|
604
|
+
title,
|
|
605
|
+
children,
|
|
606
|
+
footer,
|
|
607
|
+
className = "w-2/3",
|
|
608
|
+
width,
|
|
609
|
+
onPrint,
|
|
610
|
+
onExport,
|
|
611
|
+
modalBodyClassName,
|
|
612
|
+
modalBodyWrapperClass,
|
|
613
|
+
closeOnBackdropClick = false,
|
|
614
|
+
closeOnEscape = true,
|
|
615
|
+
zIndex = 1e3
|
|
616
|
+
}) {
|
|
617
|
+
const modalRef = useRef2(null);
|
|
618
|
+
const handleBackdropClick = (e) => {
|
|
619
|
+
if (e.target === e.currentTarget && closeOnBackdropClick) {
|
|
620
|
+
onClose();
|
|
621
|
+
}
|
|
622
|
+
};
|
|
623
|
+
useEffect2(() => {
|
|
624
|
+
const handleEscape = (e) => {
|
|
625
|
+
if (e.key === "Escape" && isOpen && closeOnEscape) {
|
|
626
|
+
onClose();
|
|
627
|
+
}
|
|
628
|
+
};
|
|
629
|
+
if (isOpen) {
|
|
630
|
+
document.addEventListener("keydown", handleEscape);
|
|
631
|
+
document.body.style.overflow = "hidden";
|
|
632
|
+
}
|
|
633
|
+
return () => {
|
|
634
|
+
document.removeEventListener("keydown", handleEscape);
|
|
635
|
+
document.body.style.overflow = "unset";
|
|
636
|
+
};
|
|
637
|
+
}, [isOpen, onClose, closeOnEscape]);
|
|
638
|
+
const modalContent = /* @__PURE__ */ jsx4(AnimatePresence, { children: isOpen && /* @__PURE__ */ jsx4(
|
|
639
|
+
"div",
|
|
640
|
+
{
|
|
641
|
+
className: "fixed inset-0 bg-gray-500 bg-opacity-50 flex justify-center items-center p-4",
|
|
642
|
+
onClick: handleBackdropClick,
|
|
643
|
+
style: {
|
|
644
|
+
position: "fixed",
|
|
645
|
+
top: 0,
|
|
646
|
+
left: 0,
|
|
647
|
+
right: 0,
|
|
648
|
+
bottom: 0,
|
|
649
|
+
width: "100vw",
|
|
650
|
+
height: "100vh",
|
|
651
|
+
margin: 0,
|
|
652
|
+
padding: "1rem",
|
|
653
|
+
zIndex
|
|
654
|
+
},
|
|
655
|
+
children: /* @__PURE__ */ jsxs4(
|
|
656
|
+
motion.div,
|
|
657
|
+
{
|
|
658
|
+
ref: modalRef,
|
|
659
|
+
initial: { y: "-100vh", opacity: 0 },
|
|
660
|
+
animate: { y: 0, opacity: 1 },
|
|
661
|
+
exit: { y: "100vh", opacity: 0 },
|
|
662
|
+
transition: { duration: 0.3 },
|
|
663
|
+
className: cn(
|
|
664
|
+
"bg-white rounded-3xl shadow-lg max-h-[90vh] flex flex-col mx-auto",
|
|
665
|
+
className,
|
|
666
|
+
width
|
|
667
|
+
),
|
|
668
|
+
onClick: (e) => e.stopPropagation(),
|
|
669
|
+
style: {
|
|
670
|
+
maxWidth: "95vw",
|
|
671
|
+
maxHeight: "90vh"
|
|
672
|
+
},
|
|
673
|
+
children: [
|
|
674
|
+
/* @__PURE__ */ jsxs4("div", { className: "sticky top-0 z-10 flex justify-between items-center bg-white text-2xl p-8 pb-4 rounded-t-3xl", children: [
|
|
675
|
+
/* @__PURE__ */ jsx4("h2", { className: "font-semibold", children: title }),
|
|
676
|
+
/* @__PURE__ */ jsxs4("div", { className: "flex items-center space-x-4", children: [
|
|
677
|
+
onPrint && /* @__PURE__ */ jsxs4(
|
|
678
|
+
"button",
|
|
679
|
+
{
|
|
680
|
+
type: "button",
|
|
681
|
+
onClick: onPrint,
|
|
682
|
+
className: "flex items-center gap-1 hover:text-gray-300 text-sm border p-1 rounded",
|
|
683
|
+
children: [
|
|
684
|
+
/* @__PURE__ */ jsx4(FaPrint, {}),
|
|
685
|
+
/* @__PURE__ */ jsx4("span", { children: "Print" })
|
|
686
|
+
]
|
|
687
|
+
}
|
|
688
|
+
),
|
|
689
|
+
onExport && /* @__PURE__ */ jsxs4(
|
|
690
|
+
"button",
|
|
691
|
+
{
|
|
692
|
+
type: "button",
|
|
693
|
+
onClick: onExport,
|
|
694
|
+
className: "flex items-center gap-1 hover:text-gray-300 text-sm border p-1 rounded",
|
|
695
|
+
children: [
|
|
696
|
+
/* @__PURE__ */ jsx4(FaFileExport, {}),
|
|
697
|
+
/* @__PURE__ */ jsx4("span", { children: "Export" })
|
|
698
|
+
]
|
|
699
|
+
}
|
|
700
|
+
),
|
|
701
|
+
/* @__PURE__ */ jsx4(
|
|
702
|
+
"button",
|
|
703
|
+
{
|
|
704
|
+
type: "button",
|
|
705
|
+
onClick: onClose,
|
|
706
|
+
className: "px-2 hover:opacity-70 transition-opacity",
|
|
707
|
+
children: /* @__PURE__ */ jsx4(IoCloseCircleOutline, { color: "#8898AA", size: 25 })
|
|
708
|
+
}
|
|
709
|
+
)
|
|
710
|
+
] })
|
|
711
|
+
] }),
|
|
712
|
+
/* @__PURE__ */ jsx4(
|
|
713
|
+
"div",
|
|
714
|
+
{
|
|
715
|
+
className: cn(
|
|
716
|
+
"overflow-y-auto px-8 pb-8 flex-grow scroll",
|
|
717
|
+
modalBodyWrapperClass,
|
|
718
|
+
modalBodyClassName
|
|
719
|
+
),
|
|
720
|
+
children
|
|
721
|
+
}
|
|
722
|
+
),
|
|
723
|
+
footer && /* @__PURE__ */ jsx4("div", { className: "sticky bottom-0 flex justify-end p-4 space-x-4 border-t bg-white rounded-b-3xl", children: footer })
|
|
724
|
+
]
|
|
725
|
+
}
|
|
726
|
+
)
|
|
727
|
+
}
|
|
728
|
+
) });
|
|
729
|
+
let modalRoot = document.getElementById("modal-root");
|
|
730
|
+
if (!modalRoot) {
|
|
731
|
+
modalRoot = document.createElement("div");
|
|
732
|
+
modalRoot.id = "modal-root";
|
|
733
|
+
document.body.appendChild(modalRoot);
|
|
734
|
+
}
|
|
735
|
+
return createPortal(modalContent, modalRoot);
|
|
736
|
+
}
|
|
737
|
+
|
|
534
738
|
export {
|
|
535
739
|
EztrakTabs,
|
|
536
740
|
ResetColumnsButton,
|
|
537
741
|
TableLayoutToolbarControls,
|
|
538
|
-
CustomPagination
|
|
742
|
+
CustomPagination,
|
|
743
|
+
ResetFiltersButton,
|
|
744
|
+
Modal
|
|
539
745
|
};
|
|
540
|
-
//# sourceMappingURL=chunk-
|
|
746
|
+
//# sourceMappingURL=chunk-BI64GTKG.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/tabs/EztrakTabs.tsx","../src/components/pagination/CustomPagination.tsx","../src/components/search-filters/ResetFiltersButton.tsx","../src/components/modal/Modal.tsx"],"sourcesContent":["import {\r\n useCallback,\r\n useEffect,\r\n useId,\r\n useRef,\r\n useState,\r\n type KeyboardEvent,\r\n} from \"react\";\r\nimport { cn } from \"../../utils/cn\";\r\nimport type { EztrakTab, EztrakTabsProps } from \"./types\";\r\n\r\nfunction getInitialTabId(\r\n tabs: EztrakTab[],\r\n defaultTabId?: string\r\n): string | undefined {\r\n if (defaultTabId && tabs.some((t) => t.id === defaultTabId && !t.disabled)) {\r\n return defaultTabId;\r\n }\r\n return tabs.find((t) => !t.disabled)?.id;\r\n}\r\n\r\nfunction getEnabledTabIds(tabs: EztrakTab[]): string[] {\r\n return tabs.filter((t) => !t.disabled).map((t) => t.id);\r\n}\r\n\r\nexport function EztrakTabs({\r\n tabs,\r\n activeTab,\r\n defaultTabId,\r\n onTabChange,\r\n showPanels = true,\r\n keepMounted = false,\r\n classNames,\r\n className,\r\n}: EztrakTabsProps) {\r\n const baseId = useId().replace(/:/g, \"\");\r\n const isControlled = activeTab !== undefined && activeTab !== null;\r\n const [uncontrolledActive, setUncontrolledActive] = useState(() =>\r\n getInitialTabId(tabs, defaultTabId)\r\n );\r\n const tabRefs = useRef<Map<string, HTMLButtonElement>>(new Map());\r\n\r\n const displayActive = isControlled ? activeTab : uncontrolledActive;\r\n\r\n useEffect(() => {\r\n if (isControlled) return;\r\n const enabledIds = getEnabledTabIds(tabs);\r\n if (!displayActive || !enabledIds.includes(displayActive)) {\r\n const next = getInitialTabId(tabs, defaultTabId);\r\n if (next !== displayActive) {\r\n setUncontrolledActive(next);\r\n }\r\n }\r\n }, [tabs, defaultTabId, isControlled, displayActive]);\r\n\r\n const handleTabClick = useCallback(\r\n (tabId: string, disabled?: boolean) => {\r\n if (disabled) return;\r\n if (!isControlled) {\r\n setUncontrolledActive(tabId);\r\n }\r\n onTabChange?.(tabId);\r\n },\r\n [isControlled, onTabChange]\r\n );\r\n\r\n const focusTab = useCallback((tabId: string) => {\r\n tabRefs.current.get(tabId)?.focus();\r\n }, []);\r\n\r\n const handleListKeyDown = useCallback(\r\n (event: KeyboardEvent<HTMLUListElement>) => {\r\n const enabledIds = getEnabledTabIds(tabs);\r\n if (enabledIds.length === 0) return;\r\n\r\n const currentIndex = displayActive\r\n ? enabledIds.indexOf(displayActive)\r\n : -1;\r\n let nextIndex = currentIndex;\r\n\r\n switch (event.key) {\r\n case \"ArrowRight\":\r\n case \"ArrowDown\":\r\n event.preventDefault();\r\n nextIndex =\r\n currentIndex < 0\r\n ? 0\r\n : (currentIndex + 1) % enabledIds.length;\r\n break;\r\n case \"ArrowLeft\":\r\n case \"ArrowUp\":\r\n event.preventDefault();\r\n nextIndex =\r\n currentIndex < 0\r\n ? enabledIds.length - 1\r\n : (currentIndex - 1 + enabledIds.length) % enabledIds.length;\r\n break;\r\n case \"Home\":\r\n event.preventDefault();\r\n nextIndex = 0;\r\n break;\r\n case \"End\":\r\n event.preventDefault();\r\n nextIndex = enabledIds.length - 1;\r\n break;\r\n default:\r\n return;\r\n }\r\n\r\n const nextId = enabledIds[nextIndex];\r\n if (nextId) {\r\n handleTabClick(nextId);\r\n focusTab(nextId);\r\n }\r\n },\r\n [tabs, displayActive, handleTabClick, focusTab]\r\n );\r\n\r\n if (!tabs.length) {\r\n return null;\r\n }\r\n\r\n const wrapperClass = cn(\r\n \"eztrak-tabs-wrapper\",\r\n classNames?.wrapper,\r\n className\r\n );\r\n\r\n return (\r\n <div className={wrapperClass}>\r\n <div className={cn(\"eztrak-tabs-container\", classNames?.container)}>\r\n <nav\r\n className={cn(\"eztrak-tabs-nav\", classNames?.nav)}\r\n aria-label=\"Tabs\"\r\n >\r\n <ul\r\n role=\"tablist\"\r\n className={cn(\"eztrak-tabs-list\", classNames?.list)}\r\n onKeyDown={handleListKeyDown}\r\n >\r\n {tabs.map((tab) => {\r\n const isActive = displayActive === tab.id;\r\n const tabId = `${baseId}-tab-${tab.id}`;\r\n const panelId = `${baseId}-panel-${tab.id}`;\r\n\r\n return (\r\n <li\r\n key={tab.id}\r\n role=\"presentation\"\r\n className={cn(\r\n \"eztrak-tabs-item\",\r\n isActive && \"eztrak-tabs-item-active\",\r\n classNames?.item,\r\n isActive && classNames?.itemActive\r\n )}\r\n >\r\n <button\r\n ref={(el) => {\r\n if (el) {\r\n tabRefs.current.set(tab.id, el);\r\n } else {\r\n tabRefs.current.delete(tab.id);\r\n }\r\n }}\r\n type=\"button\"\r\n role=\"tab\"\r\n id={tabId}\r\n aria-selected={isActive}\r\n aria-controls={showPanels ? panelId : undefined}\r\n tabIndex={isActive ? 0 : -1}\r\n disabled={tab.disabled}\r\n className={cn(\r\n \"eztrak-tabs-button\",\r\n isActive && \"eztrak-tabs-button-active\",\r\n classNames?.button,\r\n isActive && classNames?.buttonActive\r\n )}\r\n onClick={() => handleTabClick(tab.id, tab.disabled)}\r\n >\r\n {tab.icon ? (\r\n <span\r\n className={cn(\"eztrak-tabs-icon\", classNames?.icon)}\r\n aria-hidden\r\n >\r\n {tab.icon}\r\n </span>\r\n ) : null}\r\n <span\r\n className={cn(\"eztrak-tabs-label\", classNames?.label)}\r\n >\r\n {tab.label}\r\n </span>\r\n {isActive ? (\r\n <span\r\n className={cn(\r\n \"eztrak-tabs-underline\",\r\n classNames?.underline\r\n )}\r\n aria-hidden\r\n />\r\n ) : null}\r\n </button>\r\n </li>\r\n );\r\n })}\r\n </ul>\r\n </nav>\r\n\r\n {showPanels ? (\r\n <div className={cn(\"eztrak-tabs-content\", classNames?.content)}>\r\n {tabs.map((tab) => {\r\n const isActive = displayActive === tab.id;\r\n const panelId = `${baseId}-panel-${tab.id}`;\r\n const tabId = `${baseId}-tab-${tab.id}`;\r\n\r\n if (!keepMounted && !isActive) {\r\n return null;\r\n }\r\n\r\n return (\r\n <div\r\n key={tab.id}\r\n id={panelId}\r\n role=\"tabpanel\"\r\n aria-labelledby={tabId}\r\n hidden={!isActive}\r\n className={cn(\"eztrak-tabs-panel\", classNames?.panel)}\r\n >\r\n {tab.content}\r\n </div>\r\n );\r\n })}\r\n </div>\r\n ) : null}\r\n </div>\r\n </div>\r\n );\r\n}\r\n","import { type ChangeEvent, type ReactNode } from \"react\";\r\nimport { useSearchParams } from \"react-router-dom\";\r\nimport { cn } from \"../../utils/cn\";\r\nimport { confirmationAlert } from \"../../utils/handleApiError\";\r\nimport type {\r\n CustomPaginationProps,\r\n ResetColumnsButtonProps,\r\n TableLayoutToolbarControlsProps,\r\n} from \"./types\";\r\n\r\nconst DEFAULT_PAGE_SIZE_OPTIONS = [10, 20, 30, 50, 100];\r\nconst ALL_PAGES_VALUE = -1;\r\n\r\nfunction padCount(num: number) {\r\n return num.toString().padStart(2, \"0\");\r\n}\r\n\r\nfunction RefreshIcon({\r\n size = 14,\r\n className,\r\n}: {\r\n size?: number;\r\n className?: string;\r\n}) {\r\n return (\r\n <svg\r\n width={size}\r\n height={size}\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n strokeWidth=\"2\"\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n aria-hidden=\"true\"\r\n className={className}\r\n >\r\n <path d=\"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8\" />\r\n <path d=\"M21 3v5h-5\" />\r\n <path d=\"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16\" />\r\n <path d=\"M8 16H3v5\" />\r\n </svg>\r\n );\r\n}\r\n\r\nexport function ResetColumnsButton({\r\n onReset,\r\n disabled = false,\r\n isLoading = false,\r\n}: ResetColumnsButtonProps) {\r\n const handleClick = () => {\r\n confirmationAlert(onReset, {\r\n text: \"Reset column order, widths, and visibility to defaults?\",\r\n icon: \"warning\",\r\n title: \"Reset column layout to default\",\r\n });\r\n };\r\n\r\n return (\r\n <button\r\n type=\"button\"\r\n onClick={handleClick}\r\n disabled={disabled || isLoading}\r\n title=\"Reset column layout to default\"\r\n className=\"inline-flex items-center gap-1.5 rounded-xl border border-primary-150 bg-white px-3 py-1.5 text-sm font-medium text-primary-150 hover:bg-gray-50 focus:outline-none disabled:hover:bg-white\"\r\n >\r\n <RefreshIcon size={14} className={cn(isLoading ? \"animate-spin\" : \"\")} />\r\n Reset columns\r\n </button>\r\n );\r\n}\r\n\r\nexport function TableLayoutToolbarControls({\r\n layoutStatus = {},\r\n onResetLayout,\r\n renderResetControl,\r\n isLoading = false,\r\n}: TableLayoutToolbarControlsProps) {\r\n const { isLayoutLoading, isLayoutSaving, isLayoutResetting } = layoutStatus;\r\n const isLayoutBusy = isLayoutLoading || isLayoutSaving || isLayoutResetting;\r\n\r\n return (\r\n <div className=\"flex items-center gap-3\">\r\n {onResetLayout &&\r\n (renderResetControl ? (\r\n renderResetControl(onResetLayout)\r\n ) : (\r\n <ResetColumnsButton\r\n onReset={onResetLayout}\r\n disabled={isLayoutBusy}\r\n isLoading={isLoading}\r\n />\r\n ))}\r\n </div>\r\n );\r\n}\r\n\r\nexport function CustomPagination({\r\n paginationData,\r\n paginationPageSize,\r\n pageSizeOptions: pageSizeOptionsProp,\r\n isLoading = false,\r\n paramNames,\r\n onPageChange,\r\n onPageSizeChange,\r\n onResetLayout,\r\n renderResetControl,\r\n layoutStatus,\r\n showAllPagesOption = false,\r\n classNames,\r\n className,\r\n}: CustomPaginationProps) {\r\n const [searchParams, setSearchParams] = useSearchParams();\r\n const pageKey = paramNames?.page ?? \"page\";\r\n const perPageKey = paramNames?.perPage ?? \"perPage\";\r\n const pageSizeOptions =\r\n pageSizeOptionsProp ?? paginationPageSize ?? DEFAULT_PAGE_SIZE_OPTIONS;\r\n const perPageParam = searchParams.get(perPageKey);\r\n const perPageNumber =\r\n perPageParam !== null && perPageParam !== \"\"\r\n ? parseInt(perPageParam, 10)\r\n : NaN;\r\n const isShowingAll = perPageNumber === ALL_PAGES_VALUE;\r\n\r\n const currentPage = paginationData\r\n ? Math.max(0, paginationData.currentPage - 1)\r\n : 0;\r\n\r\n const handlePageChange = (pageNumber: number) => {\r\n if (\r\n !paginationData ||\r\n pageNumber < 0 ||\r\n pageNumber >= paginationData.pageCount\r\n ) {\r\n return;\r\n }\r\n\r\n const safePage = Math.max(\r\n 1,\r\n Math.min(pageNumber + 1, paginationData.pageCount)\r\n );\r\n const newParams = new URLSearchParams(searchParams);\r\n newParams.set(pageKey, String(safePage));\r\n setSearchParams(newParams, { replace: true });\r\n onPageChange?.(safePage);\r\n };\r\n\r\n const handlePageSizeChange = (event: ChangeEvent<HTMLSelectElement>) => {\r\n const parsed = parseInt(event.target.value, 10);\r\n if (\r\n !Number.isFinite(parsed) ||\r\n (parsed < 1 && parsed !== ALL_PAGES_VALUE)\r\n ) {\r\n return;\r\n }\r\n\r\n const newParams = new URLSearchParams(searchParams);\r\n newParams.set(pageKey, \"1\");\r\n newParams.set(perPageKey, String(parsed));\r\n setSearchParams(newParams, { replace: true });\r\n onPageSizeChange?.(parsed);\r\n };\r\n\r\n const createPageButtons = () => {\r\n const buttons: ReactNode[] = [];\r\n const maxButtons = 5;\r\n const totalPages = Math.max(1, paginationData?.pageCount ?? 1);\r\n\r\n let startPage = Math.max(0, currentPage - Math.floor(maxButtons / 2));\r\n let endPage = Math.min(totalPages - 1, startPage + maxButtons - 1);\r\n\r\n if (endPage - startPage + 1 < maxButtons) {\r\n startPage = Math.max(0, endPage - maxButtons + 1);\r\n }\r\n\r\n if (startPage > 0) {\r\n buttons.push(\r\n <button\r\n key=\"1\"\r\n type=\"button\"\r\n onClick={() => handlePageChange(0)}\r\n aria-label=\"Page 1\"\r\n className={cn(\r\n \"px-3 py-2 text-sm text-gray-600 hover:text-blue-600 hover:bg-blue-50 rounded-md transition-colors\",\r\n classNames?.pageButton\r\n )}\r\n >\r\n 1\r\n </button>\r\n );\r\n\r\n if (startPage > 1) {\r\n buttons.push(\r\n <span\r\n key=\"ellipsis1\"\r\n aria-hidden=\"true\"\r\n className=\"px-2 py-2 text-gray-400\"\r\n >\r\n ...\r\n </span>\r\n );\r\n }\r\n }\r\n\r\n for (let i = startPage; i <= endPage; i++) {\r\n const isActive = currentPage === i;\r\n buttons.push(\r\n <button\r\n key={i + 1}\r\n type=\"button\"\r\n onClick={() => handlePageChange(i)}\r\n aria-label={`Page ${i + 1}`}\r\n aria-current={isActive ? \"page\" : undefined}\r\n className={cn(\r\n \"px-3 py-2 text-sm rounded-md transition-colors\",\r\n isActive\r\n ? cn(\"bg-gray-400 text-white\", classNames?.activePageButton)\r\n : cn(\r\n \"text-gray-600 hover:text-gray-600 hover:bg-gray-50\",\r\n classNames?.pageButton\r\n )\r\n )}\r\n >\r\n {i + 1}\r\n </button>\r\n );\r\n }\r\n\r\n if (endPage < totalPages - 1) {\r\n if (endPage < totalPages - 2) {\r\n buttons.push(\r\n <span\r\n key=\"ellipsis2\"\r\n aria-hidden=\"true\"\r\n className=\"px-2 py-2 text-gray-400\"\r\n >\r\n ...\r\n </span>\r\n );\r\n }\r\n\r\n buttons.push(\r\n <button\r\n key={totalPages}\r\n type=\"button\"\r\n onClick={() => handlePageChange(totalPages - 1)}\r\n aria-label={`Page ${totalPages}`}\r\n className={cn(\r\n \"px-3 py-2 text-sm text-gray-600 hover:text-gray-600 hover:bg-gray-50 rounded-md transition-colors\",\r\n classNames?.pageButton\r\n )}\r\n >\r\n {totalPages}\r\n </button>\r\n );\r\n }\r\n\r\n return buttons;\r\n };\r\n\r\n if (isLoading || !paginationData) {\r\n return (\r\n <div className=\"flex items-center justify-center p-6 bg-gray-50\">\r\n <span className=\"text-gray-500\">\r\n {isLoading ? \"Loading...\" : \"No pagination data\"}\r\n </span>\r\n </div>\r\n );\r\n }\r\n\r\n const effectiveSizeOptions =\r\n paginationData.perPage > 0 &&\r\n !pageSizeOptions.includes(paginationData.perPage)\r\n ? [...pageSizeOptions, paginationData.perPage].sort((a, b) => a - b)\r\n : pageSizeOptions;\r\n\r\n const selectValue = isShowingAll\r\n ? ALL_PAGES_VALUE\r\n : paginationData.perPage ||\r\n (Number.isFinite(perPageNumber) && perPageNumber > 0\r\n ? perPageNumber\r\n : 10);\r\n\r\n const startItem =\r\n paginationData.totalCount === 0\r\n ? 0\r\n : (paginationData.currentPage - 1) * paginationData.perPage + 1;\r\n const endItem = Math.min(\r\n startItem + paginationData.perPage - 1,\r\n paginationData.totalCount\r\n );\r\n\r\n const { isLayoutLoading, isLayoutSaving, isLayoutResetting } =\r\n layoutStatus ?? {};\r\n const isLayoutBusy =\r\n isLayoutLoading || isLayoutSaving || isLayoutResetting;\r\n\r\n return (\r\n <div\r\n className={cn(\r\n \"flex items-center justify-between pb-4\",\r\n className,\r\n classNames?.root\r\n )}\r\n >\r\n <div className={cn(\"flex-1\", classNames?.info)}>\r\n <span className=\"text-xs font-medium text-neutral-400\">\r\n {isShowingAll\r\n ? `Showing All ${paginationData.totalCount ?? 0} Results`\r\n : `Showing ${padCount(startItem)} - ${padCount(endItem)} of ${paginationData.totalCount ?? 0} results`}\r\n </span>\r\n </div>\r\n\r\n <nav\r\n aria-label=\"Pagination\"\r\n className={cn(\"flex items-center space-x-1\", classNames?.nav)}\r\n >\r\n <button\r\n type=\"button\"\r\n onClick={() => handlePageChange(currentPage - 1)}\r\n disabled={currentPage === 0 || isShowingAll}\r\n className=\"p-2 text-gray-400 hover:text-gray-600 disabled:opacity-30 disabled:cursor-not-allowed transition-colors\"\r\n aria-label=\"Previous page\"\r\n >\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"currentColor\">\r\n <path d=\"M10.7 2.3a1 1 0 0 1 0 1.4L6.4 8l4.3 4.3a1 1 0 1 1-1.4 1.4l-5-5a1 1 0 0 1 0-1.4l5-5a1 1 0 0 1 1.4 0z\" />\r\n </svg>\r\n </button>\r\n\r\n <div className=\"flex items-center space-x-1\">\r\n {isShowingAll ? (\r\n <span className=\"px-3 py-2 text-sm text-gray-400\" aria-hidden=\"true\">\r\n All\r\n </span>\r\n ) : (\r\n createPageButtons()\r\n )}\r\n </div>\r\n\r\n <button\r\n type=\"button\"\r\n onClick={() => handlePageChange(currentPage + 1)}\r\n disabled={\r\n currentPage >= paginationData.pageCount - 1 || isShowingAll\r\n }\r\n className=\"p-2 text-gray-400 hover:text-gray-600 disabled:opacity-30 disabled:cursor-not-allowed transition-colors\"\r\n aria-label=\"Next page\"\r\n >\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"currentColor\">\r\n <path d=\"M5.3 13.7a1 1 0 0 1 0-1.4L9.6 8 5.3 3.7a1 1 0 0 1 1.4-1.4l5 5a1 1 0 0 1 0 1.4l-5 5a1 1 0 0 1-1.4 0z\" />\r\n </svg>\r\n </button>\r\n </nav>\r\n\r\n <div className=\"flex-1 flex justify-end\">\r\n <div className=\"flex items-center gap-3\">\r\n {onResetLayout &&\r\n (renderResetControl ? (\r\n renderResetControl(onResetLayout)\r\n ) : (\r\n <ResetColumnsButton\r\n onReset={onResetLayout}\r\n disabled={isLayoutBusy}\r\n isLoading={isLoading}\r\n />\r\n ))}\r\n <div className=\"flex items-center space-x-2\">\r\n <label\r\n htmlFor=\"pagination-per-page\"\r\n className=\"text-sm text-gray-600\"\r\n >\r\n Items per page\r\n </label>\r\n <select\r\n id=\"pagination-per-page\"\r\n value={selectValue}\r\n onChange={handlePageSizeChange}\r\n className={cn(\r\n \"px-3 py-1.5 text-sm border border-gray-300 rounded-md bg-white text-gray-700 hover:border-gray-400 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-colors\",\r\n classNames?.select\r\n )}\r\n >\r\n {showAllPagesOption && (\r\n <option value={ALL_PAGES_VALUE}>All</option>\r\n )}\r\n {effectiveSizeOptions.map((option) => (\r\n <option key={option} value={option}>\r\n {option}\r\n </option>\r\n ))}\r\n </select>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n}\r\n\r\nexport default CustomPagination;\r\n","import { useSearchParams } from \"react-router-dom\";\r\nimport { cn } from \"../../utils/cn\";\r\nimport type { ResetFiltersButtonProps } from \"./types\";\r\n\r\nfunction ResetIcon({\r\n size = 16,\r\n className,\r\n}: {\r\n size?: number;\r\n className?: string;\r\n}) {\r\n return (\r\n <svg\r\n width={size}\r\n height={size}\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n strokeWidth=\"2\"\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n aria-hidden=\"true\"\r\n className={className}\r\n >\r\n <path d=\"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8\" />\r\n <path d=\"M21 3v5h-5\" />\r\n <path d=\"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16\" />\r\n <path d=\"M8 16H3v5\" />\r\n </svg>\r\n );\r\n}\r\n\r\nexport function ResetFiltersButton({\r\n label = \"Reset Filters\",\r\n icon,\r\n className,\r\n onReset,\r\n disabled = false,\r\n}: ResetFiltersButtonProps) {\r\n const [, setSearchParams] = useSearchParams();\r\n\r\n const handleReset = () => {\r\n setSearchParams({}, { replace: true });\r\n onReset?.();\r\n };\r\n\r\n const resolvedIcon = icon === undefined ? <ResetIcon size={16} /> : icon;\r\n\r\n return (\r\n <button\r\n type=\"button\"\r\n onClick={handleReset}\r\n disabled={disabled}\r\n className={cn(\r\n \"inline-flex items-center gap-1.5 rounded-xl border border-primary-150 bg-white px-3 py-1.5 text-sm font-medium text-primary-150 hover:bg-gray-50 focus:outline-none disabled:cursor-not-allowed disabled:opacity-50 disabled:hover:bg-white\",\r\n className\r\n )}\r\n >\r\n {resolvedIcon}\r\n {label}\r\n </button>\r\n );\r\n}\r\n","import { AnimatePresence, motion } from \"framer-motion\";\r\nimport { useEffect, useRef, type MouseEvent } from \"react\";\r\nimport { createPortal } from \"react-dom\";\r\nimport { FaFileExport, FaPrint } from \"react-icons/fa\";\r\nimport { IoCloseCircleOutline } from \"react-icons/io5\";\r\nimport { cn } from \"../../utils/cn\";\r\nimport type { ModalProps } from \"./types\";\r\n\r\nexport function Modal({\r\n isOpen,\r\n onClose,\r\n title,\r\n children,\r\n footer,\r\n className = \"w-2/3\",\r\n width,\r\n onPrint,\r\n onExport,\r\n modalBodyClassName,\r\n modalBodyWrapperClass,\r\n closeOnBackdropClick = false,\r\n closeOnEscape = true,\r\n zIndex = 1000,\r\n}: ModalProps) {\r\n const modalRef = useRef<HTMLDivElement>(null);\r\n\r\n const handleBackdropClick = (e: MouseEvent<HTMLDivElement>) => {\r\n if (e.target === e.currentTarget && closeOnBackdropClick) {\r\n onClose();\r\n }\r\n };\r\n\r\n useEffect(() => {\r\n const handleEscape = (e: KeyboardEvent) => {\r\n if (e.key === \"Escape\" && isOpen && closeOnEscape) {\r\n onClose();\r\n }\r\n };\r\n\r\n if (isOpen) {\r\n document.addEventListener(\"keydown\", handleEscape);\r\n document.body.style.overflow = \"hidden\";\r\n }\r\n\r\n return () => {\r\n document.removeEventListener(\"keydown\", handleEscape);\r\n document.body.style.overflow = \"unset\";\r\n };\r\n }, [isOpen, onClose, closeOnEscape]);\r\n\r\n const modalContent = (\r\n <AnimatePresence>\r\n {isOpen && (\r\n <div\r\n className=\"fixed inset-0 bg-gray-500 bg-opacity-50 flex justify-center items-center p-4\"\r\n onClick={handleBackdropClick}\r\n style={{\r\n position: \"fixed\",\r\n top: 0,\r\n left: 0,\r\n right: 0,\r\n bottom: 0,\r\n width: \"100vw\",\r\n height: \"100vh\",\r\n margin: 0,\r\n padding: \"1rem\",\r\n zIndex,\r\n }}\r\n >\r\n <motion.div\r\n ref={modalRef}\r\n initial={{ y: \"-100vh\", opacity: 0 }}\r\n animate={{ y: 0, opacity: 1 }}\r\n exit={{ y: \"100vh\", opacity: 0 }}\r\n transition={{ duration: 0.3 }}\r\n className={cn(\r\n \"bg-white rounded-3xl shadow-lg max-h-[90vh] flex flex-col mx-auto\",\r\n className,\r\n width\r\n )}\r\n onClick={(e) => e.stopPropagation()}\r\n style={{\r\n maxWidth: \"95vw\",\r\n maxHeight: \"90vh\",\r\n }}\r\n >\r\n <div className=\"sticky top-0 z-10 flex justify-between items-center bg-white text-2xl p-8 pb-4 rounded-t-3xl\">\r\n <h2 className=\"font-semibold\">{title}</h2>\r\n <div className=\"flex items-center space-x-4\">\r\n {onPrint && (\r\n <button\r\n type=\"button\"\r\n onClick={onPrint}\r\n className=\"flex items-center gap-1 hover:text-gray-300 text-sm border p-1 rounded\"\r\n >\r\n <FaPrint />\r\n <span>Print</span>\r\n </button>\r\n )}\r\n {onExport && (\r\n <button\r\n type=\"button\"\r\n onClick={onExport}\r\n className=\"flex items-center gap-1 hover:text-gray-300 text-sm border p-1 rounded\"\r\n >\r\n <FaFileExport />\r\n <span>Export</span>\r\n </button>\r\n )}\r\n <button\r\n type=\"button\"\r\n onClick={onClose}\r\n className=\"px-2 hover:opacity-70 transition-opacity\"\r\n >\r\n <IoCloseCircleOutline color=\"#8898AA\" size={25} />\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <div\r\n className={cn(\r\n \"overflow-y-auto px-8 pb-8 flex-grow scroll\",\r\n modalBodyWrapperClass,\r\n modalBodyClassName\r\n )}\r\n >\r\n {children}\r\n </div>\r\n\r\n {footer && (\r\n <div className=\"sticky bottom-0 flex justify-end p-4 space-x-4 border-t bg-white rounded-b-3xl\">\r\n {footer}\r\n </div>\r\n )}\r\n </motion.div>\r\n </div>\r\n )}\r\n </AnimatePresence>\r\n );\r\n\r\n let modalRoot = document.getElementById(\"modal-root\");\r\n if (!modalRoot) {\r\n modalRoot = document.createElement(\"div\");\r\n modalRoot.id = \"modal-root\";\r\n document.body.appendChild(modalRoot);\r\n }\r\n\r\n return createPortal(modalContent, modalRoot);\r\n}\r\n"],"mappings":"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","names":["jsx","jsxs","useSearchParams","jsx","jsxs","useSearchParams","useEffect","useRef","jsx","jsxs","useRef","useEffect"]}
|
|
@@ -94,4 +94,37 @@ declare function ResetColumnsButton({ onReset, disabled, isLoading, }: ResetColu
|
|
|
94
94
|
declare function TableLayoutToolbarControls({ layoutStatus, onResetLayout, renderResetControl, isLoading, }: TableLayoutToolbarControlsProps): react.JSX.Element;
|
|
95
95
|
declare function CustomPagination({ paginationData, paginationPageSize, pageSizeOptions: pageSizeOptionsProp, isLoading, paramNames, onPageChange, onPageSizeChange, onResetLayout, renderResetControl, layoutStatus, showAllPagesOption, classNames, className, }: CustomPaginationProps): react.JSX.Element;
|
|
96
96
|
|
|
97
|
-
|
|
97
|
+
interface ResetFiltersButtonProps {
|
|
98
|
+
/** Button label text. Defaults to "Reset Filters". */
|
|
99
|
+
label?: string;
|
|
100
|
+
/** Leading icon. Defaults to a reset icon; pass `null` to hide it. */
|
|
101
|
+
icon?: ReactNode;
|
|
102
|
+
/** Extra classes merged with the default button styles. */
|
|
103
|
+
className?: string;
|
|
104
|
+
/** Called after the search params are cleared. */
|
|
105
|
+
onReset?: () => void;
|
|
106
|
+
disabled?: boolean;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
declare function ResetFiltersButton({ label, icon, className, onReset, disabled, }: ResetFiltersButtonProps): react.JSX.Element;
|
|
110
|
+
|
|
111
|
+
interface ModalProps {
|
|
112
|
+
isOpen: boolean;
|
|
113
|
+
onClose: () => void;
|
|
114
|
+
title?: ReactNode;
|
|
115
|
+
children?: ReactNode;
|
|
116
|
+
footer?: ReactNode;
|
|
117
|
+
className?: string;
|
|
118
|
+
width?: string;
|
|
119
|
+
onPrint?: () => void;
|
|
120
|
+
onExport?: () => void;
|
|
121
|
+
modalBodyClassName?: string;
|
|
122
|
+
modalBodyWrapperClass?: string;
|
|
123
|
+
closeOnBackdropClick?: boolean;
|
|
124
|
+
closeOnEscape?: boolean;
|
|
125
|
+
zIndex?: number;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
declare function Modal({ isOpen, onClose, title, children, footer, className, width, onPrint, onExport, modalBodyClassName, modalBodyWrapperClass, closeOnBackdropClick, closeOnEscape, zIndex, }: ModalProps): react.ReactPortal;
|
|
129
|
+
|
|
130
|
+
export { CustomPagination, type CustomPaginationClassNames, type CustomPaginationProps, type EztrakTab, EztrakTabs, type EztrakTabsClassNames, type EztrakTabsProps, type LayoutStatus, Modal, type ModalProps, type PaginationData, ResetColumnsButton, type ResetColumnsButtonProps, ResetFiltersButton, type ResetFiltersButtonProps, TableLayoutToolbarControls, type TableLayoutToolbarControlsProps };
|
|
@@ -94,4 +94,37 @@ declare function ResetColumnsButton({ onReset, disabled, isLoading, }: ResetColu
|
|
|
94
94
|
declare function TableLayoutToolbarControls({ layoutStatus, onResetLayout, renderResetControl, isLoading, }: TableLayoutToolbarControlsProps): react.JSX.Element;
|
|
95
95
|
declare function CustomPagination({ paginationData, paginationPageSize, pageSizeOptions: pageSizeOptionsProp, isLoading, paramNames, onPageChange, onPageSizeChange, onResetLayout, renderResetControl, layoutStatus, showAllPagesOption, classNames, className, }: CustomPaginationProps): react.JSX.Element;
|
|
96
96
|
|
|
97
|
-
|
|
97
|
+
interface ResetFiltersButtonProps {
|
|
98
|
+
/** Button label text. Defaults to "Reset Filters". */
|
|
99
|
+
label?: string;
|
|
100
|
+
/** Leading icon. Defaults to a reset icon; pass `null` to hide it. */
|
|
101
|
+
icon?: ReactNode;
|
|
102
|
+
/** Extra classes merged with the default button styles. */
|
|
103
|
+
className?: string;
|
|
104
|
+
/** Called after the search params are cleared. */
|
|
105
|
+
onReset?: () => void;
|
|
106
|
+
disabled?: boolean;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
declare function ResetFiltersButton({ label, icon, className, onReset, disabled, }: ResetFiltersButtonProps): react.JSX.Element;
|
|
110
|
+
|
|
111
|
+
interface ModalProps {
|
|
112
|
+
isOpen: boolean;
|
|
113
|
+
onClose: () => void;
|
|
114
|
+
title?: ReactNode;
|
|
115
|
+
children?: ReactNode;
|
|
116
|
+
footer?: ReactNode;
|
|
117
|
+
className?: string;
|
|
118
|
+
width?: string;
|
|
119
|
+
onPrint?: () => void;
|
|
120
|
+
onExport?: () => void;
|
|
121
|
+
modalBodyClassName?: string;
|
|
122
|
+
modalBodyWrapperClass?: string;
|
|
123
|
+
closeOnBackdropClick?: boolean;
|
|
124
|
+
closeOnEscape?: boolean;
|
|
125
|
+
zIndex?: number;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
declare function Modal({ isOpen, onClose, title, children, footer, className, width, onPrint, onExport, modalBodyClassName, modalBodyWrapperClass, closeOnBackdropClick, closeOnEscape, zIndex, }: ModalProps): react.ReactPortal;
|
|
129
|
+
|
|
130
|
+
export { CustomPagination, type CustomPaginationClassNames, type CustomPaginationProps, type EztrakTab, EztrakTabs, type EztrakTabsClassNames, type EztrakTabsProps, type LayoutStatus, Modal, type ModalProps, type PaginationData, ResetColumnsButton, type ResetColumnsButtonProps, ResetFiltersButton, type ResetFiltersButtonProps, TableLayoutToolbarControls, type TableLayoutToolbarControlsProps };
|
package/dist/components/index.js
CHANGED
|
@@ -32,7 +32,9 @@ var components_exports = {};
|
|
|
32
32
|
__export(components_exports, {
|
|
33
33
|
CustomPagination: () => CustomPagination,
|
|
34
34
|
EztrakTabs: () => EztrakTabs,
|
|
35
|
+
Modal: () => Modal,
|
|
35
36
|
ResetColumnsButton: () => ResetColumnsButton,
|
|
37
|
+
ResetFiltersButton: () => ResetFiltersButton,
|
|
36
38
|
TableLayoutToolbarControls: () => TableLayoutToolbarControls
|
|
37
39
|
});
|
|
38
40
|
module.exports = __toCommonJS(components_exports);
|
|
@@ -588,11 +590,217 @@ function CustomPagination({
|
|
|
588
590
|
}
|
|
589
591
|
);
|
|
590
592
|
}
|
|
593
|
+
|
|
594
|
+
// src/components/search-filters/ResetFiltersButton.tsx
|
|
595
|
+
var import_react_router_dom2 = require("react-router-dom");
|
|
596
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
597
|
+
function ResetIcon({
|
|
598
|
+
size = 16,
|
|
599
|
+
className
|
|
600
|
+
}) {
|
|
601
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
602
|
+
"svg",
|
|
603
|
+
{
|
|
604
|
+
width: size,
|
|
605
|
+
height: size,
|
|
606
|
+
viewBox: "0 0 24 24",
|
|
607
|
+
fill: "none",
|
|
608
|
+
stroke: "currentColor",
|
|
609
|
+
strokeWidth: "2",
|
|
610
|
+
strokeLinecap: "round",
|
|
611
|
+
strokeLinejoin: "round",
|
|
612
|
+
"aria-hidden": "true",
|
|
613
|
+
className,
|
|
614
|
+
children: [
|
|
615
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8" }),
|
|
616
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M21 3v5h-5" }),
|
|
617
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16" }),
|
|
618
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M8 16H3v5" })
|
|
619
|
+
]
|
|
620
|
+
}
|
|
621
|
+
);
|
|
622
|
+
}
|
|
623
|
+
function ResetFiltersButton({
|
|
624
|
+
label = "Reset Filters",
|
|
625
|
+
icon,
|
|
626
|
+
className,
|
|
627
|
+
onReset,
|
|
628
|
+
disabled = false
|
|
629
|
+
}) {
|
|
630
|
+
const [, setSearchParams] = (0, import_react_router_dom2.useSearchParams)();
|
|
631
|
+
const handleReset = () => {
|
|
632
|
+
setSearchParams({}, { replace: true });
|
|
633
|
+
onReset?.();
|
|
634
|
+
};
|
|
635
|
+
const resolvedIcon = icon === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ResetIcon, { size: 16 }) : icon;
|
|
636
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
637
|
+
"button",
|
|
638
|
+
{
|
|
639
|
+
type: "button",
|
|
640
|
+
onClick: handleReset,
|
|
641
|
+
disabled,
|
|
642
|
+
className: cn(
|
|
643
|
+
"inline-flex items-center gap-1.5 rounded-xl border border-primary-150 bg-white px-3 py-1.5 text-sm font-medium text-primary-150 hover:bg-gray-50 focus:outline-none disabled:cursor-not-allowed disabled:opacity-50 disabled:hover:bg-white",
|
|
644
|
+
className
|
|
645
|
+
),
|
|
646
|
+
children: [
|
|
647
|
+
resolvedIcon,
|
|
648
|
+
label
|
|
649
|
+
]
|
|
650
|
+
}
|
|
651
|
+
);
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
// src/components/modal/Modal.tsx
|
|
655
|
+
var import_framer_motion = require("framer-motion");
|
|
656
|
+
var import_react2 = require("react");
|
|
657
|
+
var import_react_dom = require("react-dom");
|
|
658
|
+
var import_fa = require("react-icons/fa");
|
|
659
|
+
var import_io5 = require("react-icons/io5");
|
|
660
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
661
|
+
function Modal({
|
|
662
|
+
isOpen,
|
|
663
|
+
onClose,
|
|
664
|
+
title,
|
|
665
|
+
children,
|
|
666
|
+
footer,
|
|
667
|
+
className = "w-2/3",
|
|
668
|
+
width,
|
|
669
|
+
onPrint,
|
|
670
|
+
onExport,
|
|
671
|
+
modalBodyClassName,
|
|
672
|
+
modalBodyWrapperClass,
|
|
673
|
+
closeOnBackdropClick = false,
|
|
674
|
+
closeOnEscape = true,
|
|
675
|
+
zIndex = 1e3
|
|
676
|
+
}) {
|
|
677
|
+
const modalRef = (0, import_react2.useRef)(null);
|
|
678
|
+
const handleBackdropClick = (e) => {
|
|
679
|
+
if (e.target === e.currentTarget && closeOnBackdropClick) {
|
|
680
|
+
onClose();
|
|
681
|
+
}
|
|
682
|
+
};
|
|
683
|
+
(0, import_react2.useEffect)(() => {
|
|
684
|
+
const handleEscape = (e) => {
|
|
685
|
+
if (e.key === "Escape" && isOpen && closeOnEscape) {
|
|
686
|
+
onClose();
|
|
687
|
+
}
|
|
688
|
+
};
|
|
689
|
+
if (isOpen) {
|
|
690
|
+
document.addEventListener("keydown", handleEscape);
|
|
691
|
+
document.body.style.overflow = "hidden";
|
|
692
|
+
}
|
|
693
|
+
return () => {
|
|
694
|
+
document.removeEventListener("keydown", handleEscape);
|
|
695
|
+
document.body.style.overflow = "unset";
|
|
696
|
+
};
|
|
697
|
+
}, [isOpen, onClose, closeOnEscape]);
|
|
698
|
+
const modalContent = /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_framer_motion.AnimatePresence, { children: isOpen && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
699
|
+
"div",
|
|
700
|
+
{
|
|
701
|
+
className: "fixed inset-0 bg-gray-500 bg-opacity-50 flex justify-center items-center p-4",
|
|
702
|
+
onClick: handleBackdropClick,
|
|
703
|
+
style: {
|
|
704
|
+
position: "fixed",
|
|
705
|
+
top: 0,
|
|
706
|
+
left: 0,
|
|
707
|
+
right: 0,
|
|
708
|
+
bottom: 0,
|
|
709
|
+
width: "100vw",
|
|
710
|
+
height: "100vh",
|
|
711
|
+
margin: 0,
|
|
712
|
+
padding: "1rem",
|
|
713
|
+
zIndex
|
|
714
|
+
},
|
|
715
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
716
|
+
import_framer_motion.motion.div,
|
|
717
|
+
{
|
|
718
|
+
ref: modalRef,
|
|
719
|
+
initial: { y: "-100vh", opacity: 0 },
|
|
720
|
+
animate: { y: 0, opacity: 1 },
|
|
721
|
+
exit: { y: "100vh", opacity: 0 },
|
|
722
|
+
transition: { duration: 0.3 },
|
|
723
|
+
className: cn(
|
|
724
|
+
"bg-white rounded-3xl shadow-lg max-h-[90vh] flex flex-col mx-auto",
|
|
725
|
+
className,
|
|
726
|
+
width
|
|
727
|
+
),
|
|
728
|
+
onClick: (e) => e.stopPropagation(),
|
|
729
|
+
style: {
|
|
730
|
+
maxWidth: "95vw",
|
|
731
|
+
maxHeight: "90vh"
|
|
732
|
+
},
|
|
733
|
+
children: [
|
|
734
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "sticky top-0 z-10 flex justify-between items-center bg-white text-2xl p-8 pb-4 rounded-t-3xl", children: [
|
|
735
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h2", { className: "font-semibold", children: title }),
|
|
736
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex items-center space-x-4", children: [
|
|
737
|
+
onPrint && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
738
|
+
"button",
|
|
739
|
+
{
|
|
740
|
+
type: "button",
|
|
741
|
+
onClick: onPrint,
|
|
742
|
+
className: "flex items-center gap-1 hover:text-gray-300 text-sm border p-1 rounded",
|
|
743
|
+
children: [
|
|
744
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_fa.FaPrint, {}),
|
|
745
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "Print" })
|
|
746
|
+
]
|
|
747
|
+
}
|
|
748
|
+
),
|
|
749
|
+
onExport && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
750
|
+
"button",
|
|
751
|
+
{
|
|
752
|
+
type: "button",
|
|
753
|
+
onClick: onExport,
|
|
754
|
+
className: "flex items-center gap-1 hover:text-gray-300 text-sm border p-1 rounded",
|
|
755
|
+
children: [
|
|
756
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_fa.FaFileExport, {}),
|
|
757
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "Export" })
|
|
758
|
+
]
|
|
759
|
+
}
|
|
760
|
+
),
|
|
761
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
762
|
+
"button",
|
|
763
|
+
{
|
|
764
|
+
type: "button",
|
|
765
|
+
onClick: onClose,
|
|
766
|
+
className: "px-2 hover:opacity-70 transition-opacity",
|
|
767
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_io5.IoCloseCircleOutline, { color: "#8898AA", size: 25 })
|
|
768
|
+
}
|
|
769
|
+
)
|
|
770
|
+
] })
|
|
771
|
+
] }),
|
|
772
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
773
|
+
"div",
|
|
774
|
+
{
|
|
775
|
+
className: cn(
|
|
776
|
+
"overflow-y-auto px-8 pb-8 flex-grow scroll",
|
|
777
|
+
modalBodyWrapperClass,
|
|
778
|
+
modalBodyClassName
|
|
779
|
+
),
|
|
780
|
+
children
|
|
781
|
+
}
|
|
782
|
+
),
|
|
783
|
+
footer && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "sticky bottom-0 flex justify-end p-4 space-x-4 border-t bg-white rounded-b-3xl", children: footer })
|
|
784
|
+
]
|
|
785
|
+
}
|
|
786
|
+
)
|
|
787
|
+
}
|
|
788
|
+
) });
|
|
789
|
+
let modalRoot = document.getElementById("modal-root");
|
|
790
|
+
if (!modalRoot) {
|
|
791
|
+
modalRoot = document.createElement("div");
|
|
792
|
+
modalRoot.id = "modal-root";
|
|
793
|
+
document.body.appendChild(modalRoot);
|
|
794
|
+
}
|
|
795
|
+
return (0, import_react_dom.createPortal)(modalContent, modalRoot);
|
|
796
|
+
}
|
|
591
797
|
// Annotate the CommonJS export names for ESM import in node:
|
|
592
798
|
0 && (module.exports = {
|
|
593
799
|
CustomPagination,
|
|
594
800
|
EztrakTabs,
|
|
801
|
+
Modal,
|
|
595
802
|
ResetColumnsButton,
|
|
803
|
+
ResetFiltersButton,
|
|
596
804
|
TableLayoutToolbarControls
|
|
597
805
|
});
|
|
598
806
|
//# sourceMappingURL=index.js.map
|