ikoncomponents 1.7.7 → 1.8.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/dist/ikoncomponents/action-menu/index.d.ts +2 -1
- package/dist/ikoncomponents/activity-sheet/index.d.ts +2 -1
- package/dist/ikoncomponents/app-breadcrumb/BreadcrumbProvider.d.ts +1 -1
- package/dist/ikoncomponents/app-breadcrumb/index.d.ts +2 -2
- package/dist/ikoncomponents/big-calendar/big-calender-event/index.d.ts +1 -1
- package/dist/ikoncomponents/big-calendar/big-calender-toolbar/index.d.ts +1 -1
- package/dist/ikoncomponents/big-calendar/index.d.ts +1 -1
- package/dist/ikoncomponents/buttons/index.d.ts +6 -6
- package/dist/ikoncomponents/combobox-input/index.d.ts +2 -1
- package/dist/ikoncomponents/custom-combo-dropdown/index.d.ts +1 -1
- package/dist/ikoncomponents/data-table/datatable-column-filter/index.d.ts +2 -1
- package/dist/ikoncomponents/data-table/datatable-faceted-filter/index.d.ts +2 -1
- package/dist/ikoncomponents/data-table/datatable-filter-menu/index.d.ts +2 -1
- package/dist/ikoncomponents/data-table/datatable-pagination/index.d.ts +2 -1
- package/dist/ikoncomponents/data-table/datatable-toolbar/index.d.ts +2 -1
- package/dist/ikoncomponents/data-table/index.d.ts +2 -1
- package/dist/ikoncomponents/file-input/index.d.ts +2 -1
- package/dist/ikoncomponents/fileUpload/index.d.ts +2 -1
- package/dist/ikoncomponents/form-fields/combobox-input/index.d.ts +2 -1
- package/dist/ikoncomponents/form-fields/combobox-input-value/index.d.ts +2 -1
- package/dist/ikoncomponents/form-fields/date-input/index.d.ts +2 -1
- package/dist/ikoncomponents/form-fields/file-input/index.d.ts +2 -1
- package/dist/ikoncomponents/form-fields/input/index.d.ts +2 -1
- package/dist/ikoncomponents/form-fields/multi-combobox-input/index.d.ts +2 -1
- package/dist/ikoncomponents/form-fields/otp-input/index.d.ts +2 -1
- package/dist/ikoncomponents/form-fields/phone-input/index.d.ts +2 -1
- package/dist/ikoncomponents/form-fields/textarea/index.d.ts +2 -1
- package/dist/ikoncomponents/glowing-effect/index.d.ts +2 -1
- package/dist/ikoncomponents/icon/index.d.ts +2 -1
- package/dist/ikoncomponents/image-cropper-upload/cropper-form/index.d.ts +1 -1
- package/dist/ikoncomponents/image-cropper-upload/cropper-form-with-modal/index.d.ts +2 -1
- package/dist/ikoncomponents/image-cropper-upload/index.d.ts +2 -2
- package/dist/ikoncomponents/loading-spinner/index.d.ts +1 -1
- package/dist/ikoncomponents/main-layout/RefreshContext.d.ts +1 -1
- package/dist/ikoncomponents/main-layout/SidebarNavContext.d.ts +1 -1
- package/dist/ikoncomponents/main-layout/app-sidebar.d.ts +1 -1
- package/dist/ikoncomponents/main-layout/app-sidebar.js +4 -1
- package/dist/ikoncomponents/main-layout/footer.d.ts +2 -1
- package/dist/ikoncomponents/main-layout/footer.js +4 -1
- package/dist/ikoncomponents/main-layout/header.d.ts +2 -1
- package/dist/ikoncomponents/main-layout/header.js +4 -1
- package/dist/ikoncomponents/main-layout/index.d.ts +1 -1
- package/dist/ikoncomponents/main-layout/index.js +9 -2
- package/dist/ikoncomponents/main-layout/main-sidebar.d.ts +2 -1
- package/dist/ikoncomponents/main-layout/main-sidebar.js +27 -9
- package/dist/ikoncomponents/main-layout/nav-main.d.ts +1 -1
- package/dist/ikoncomponents/main-layout/sidebar-expanded-context.d.ts +20 -0
- package/dist/ikoncomponents/main-layout/sidebar-expanded-context.js +25 -0
- package/dist/ikoncomponents/multi-combobox/index.d.ts +2 -1
- package/dist/ikoncomponents/no-data/index.d.ts +2 -1
- package/dist/ikoncomponents/page-wrapper/index.d.ts +2 -2
- package/dist/ikoncomponents/password-strength-meter/index.d.ts +2 -1
- package/dist/ikoncomponents/phone-input/index.d.ts +2 -1
- package/dist/ikoncomponents/provider-wrapper/index.d.ts +1 -1
- package/dist/ikoncomponents/reload-component/index.d.ts +1 -1
- package/dist/ikoncomponents/search-input/index.d.ts +2 -1
- package/dist/ikoncomponents/sheet/index.d.ts +1 -1
- package/dist/ikoncomponents/simple-widget/index.d.ts +2 -2
- package/dist/ikoncomponents/skeleton-loader/skeleton-table.d.ts +1 -1
- package/dist/ikoncomponents/skeleton-loader/skeleton-widget.d.ts +1 -1
- package/dist/ikoncomponents/table/DataTable/index.d.ts +3 -2
- package/dist/ikoncomponents/table/DataTable/index.js +296 -60
- package/dist/ikoncomponents/table/DataTableColumn/index.d.ts +3 -0
- package/dist/ikoncomponents/table/DataTableColumn/index.js +17 -0
- package/dist/ikoncomponents/table/DataTableFilter/index.d.ts +7 -0
- package/dist/ikoncomponents/table/DataTableFilter/index.js +95 -0
- package/dist/ikoncomponents/table/DataTablePageSize/index.d.ts +1 -1
- package/dist/ikoncomponents/table/DataTablePageSize/index.js +2 -0
- package/dist/ikoncomponents/table/DataTablePagination/index.d.ts +2 -2
- package/dist/ikoncomponents/table/DataTablePagination/index.js +3 -1
- package/dist/ikoncomponents/table/DataTableSearch/index.d.ts +1 -1
- package/dist/ikoncomponents/table/DataTableSearch/index.js +16 -4
- package/dist/ikoncomponents/table/index.d.ts +2 -2
- package/dist/ikoncomponents/table/index.js +2 -162
- package/dist/ikoncomponents/table/type.d.ts +83 -24
- package/dist/ikoncomponents/table/type.js +0 -7
- package/dist/ikoncomponents/tabs/index.d.ts +2 -1
- package/dist/ikoncomponents/theme-toggle-btn/index.d.ts +1 -1
- package/dist/ikoncomponents/title-progress/index.d.ts +2 -1
- package/dist/ikoncomponents/tooltip/index.d.ts +1 -1
- package/dist/ikoncomponents/twolevel-dropdown/index.d.ts +2 -1
- package/dist/ikoncomponents/upload-tab/index.d.ts +1 -1
- package/dist/ikoncomponents/widgets/index.d.ts +2 -1
- package/dist/ikoncomponents/work-in-progress/index.d.ts +2 -1
- package/dist/index.d.ts +1 -1
- package/dist/shadcn/accordion.d.ts +4 -4
- package/dist/shadcn/alert-dialog.d.ts +2 -2
- package/dist/shadcn/alert.d.ts +3 -3
- package/dist/shadcn/aspect-ratio.d.ts +1 -1
- package/dist/shadcn/avatar.d.ts +3 -3
- package/dist/shadcn/badge.d.ts +1 -1
- package/dist/shadcn/breadcrumb.d.ts +7 -7
- package/dist/shadcn/button.d.ts +1 -1
- package/dist/shadcn/calendar.d.ts +2 -2
- package/dist/shadcn/card.d.ts +7 -7
- package/dist/shadcn/checkbox.d.ts +1 -1
- package/dist/shadcn/collapsible.d.ts +3 -3
- package/dist/shadcn/command.d.ts +9 -9
- package/dist/shadcn/dialog.d.ts +10 -10
- package/dist/shadcn/drawer.d.ts +10 -10
- package/dist/shadcn/dropdown-menu.d.ts +15 -15
- package/dist/shadcn/form.d.ts +7 -7
- package/dist/shadcn/hover-card.d.ts +3 -3
- package/dist/shadcn/input.d.ts +1 -1
- package/dist/shadcn/label.d.ts +1 -1
- package/dist/shadcn/navigation-menu.d.ts +8 -8
- package/dist/shadcn/popover.d.ts +4 -4
- package/dist/shadcn/progress.d.ts +1 -1
- package/dist/shadcn/radio-group.d.ts +2 -2
- package/dist/shadcn/scroll-area.d.ts +2 -2
- package/dist/shadcn/select.d.ts +10 -10
- package/dist/shadcn/separator.d.ts +1 -1
- package/dist/shadcn/sheet.d.ts +8 -8
- package/dist/shadcn/sidebar.d.ts +23 -23
- package/dist/shadcn/skeleton.d.ts +1 -1
- package/dist/shadcn/slider.d.ts +1 -1
- package/dist/shadcn/sonner.d.ts +1 -1
- package/dist/shadcn/switch.d.ts +1 -1
- package/dist/shadcn/table.d.ts +8 -8
- package/dist/shadcn/tabs.d.ts +4 -4
- package/dist/shadcn/textarea.d.ts +1 -1
- package/dist/shadcn/toggle-group.d.ts +2 -2
- package/dist/shadcn/toggle.d.ts +1 -1
- package/dist/shadcn/tooltip.d.ts +4 -4
- package/dist/shadcn/workflow.d.ts +1 -1
- package/dist/styles.css +47 -28
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/utils/border-radius-provider.d.ts +1 -1
- package/dist/utils/font-provider.d.ts +1 -1
- package/dist/utils/theme-provider/index.d.ts +1 -1
- package/package.json +3 -2
- package/dist/ikoncomponents/assistant-ui/Assistant.d.ts +0 -28
- package/dist/ikoncomponents/assistant-ui/Assistant.js +0 -306
- package/dist/ikoncomponents/assistant-ui/agent-dropdown.d.ts +0 -24
- package/dist/ikoncomponents/assistant-ui/agent-dropdown.js +0 -16
- package/dist/ikoncomponents/assistant-ui/agentTextChatTransport.d.ts +0 -30
- package/dist/ikoncomponents/assistant-ui/agentTextChatTransport.js +0 -208
- package/dist/ikoncomponents/assistant-ui/attachment.d.ts +0 -4
- package/dist/ikoncomponents/assistant-ui/attachment.js +0 -93
- package/dist/ikoncomponents/assistant-ui/markdown-text.d.ts +0 -2
- package/dist/ikoncomponents/assistant-ui/markdown-text.js +0 -126
- package/dist/ikoncomponents/assistant-ui/thread.d.ts +0 -10
- package/dist/ikoncomponents/assistant-ui/thread.js +0 -115
- package/dist/ikoncomponents/assistant-ui/tool-fallback.d.ts +0 -2
- package/dist/ikoncomponents/assistant-ui/tool-fallback.js +0 -18
- package/dist/ikoncomponents/assistant-ui/tooltip-icon-button.d.ts +0 -7
- package/dist/ikoncomponents/assistant-ui/tooltip-icon-button.js +0 -23
- package/dist/utils/userType.d.ts +0 -13
- package/dist/utils/userType.js +0 -1
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { ReactNode } from "react";
|
|
1
|
+
import React, { ReactNode } from "react";
|
|
2
2
|
interface Props {
|
|
3
3
|
title?: string | ReactNode;
|
|
4
4
|
subtitle?: string | ReactNode;
|
|
5
5
|
tools?: ReactNode;
|
|
6
6
|
children: ReactNode;
|
|
7
7
|
}
|
|
8
|
-
export declare function PageWrapper({ title, subtitle, tools, children }: Props):
|
|
8
|
+
export declare function PageWrapper({ title, subtitle, tools, children }: Props): React.JSX.Element;
|
|
9
9
|
export {};
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export declare function PhoneInput({ className, ...props }: any): React.JSX.Element;
|
|
@@ -3,4 +3,4 @@ export interface ReloadProps {
|
|
|
3
3
|
onReload?: () => void;
|
|
4
4
|
errorMessage?: string;
|
|
5
5
|
}
|
|
6
|
-
export declare function Reload({ isLoading, onReload, errorMessage, }: ReloadProps): import("react
|
|
6
|
+
export declare function Reload({ isLoading, onReload, errorMessage, }: ReloadProps): import("react").JSX.Element | null;
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export declare function SearchInput({ className, ...props }: any): React.JSX.Element;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ReactNode } from "react";
|
|
1
|
+
import React, { ReactNode } from "react";
|
|
2
2
|
interface Props {
|
|
3
3
|
title: string;
|
|
4
4
|
iconName?: string;
|
|
@@ -10,5 +10,5 @@ interface Props {
|
|
|
10
10
|
loading?: boolean;
|
|
11
11
|
loadingMessage?: string;
|
|
12
12
|
}
|
|
13
|
-
export declare function SimpleWidget({ title, iconName, iconSize, iconClass, primaryText, secondaryText, mainClassName, loading, loadingMessage }: Props):
|
|
13
|
+
export declare function SimpleWidget({ title, iconName, iconSize, iconClass, primaryText, secondaryText, mainClassName, loading, loadingMessage }: Props): React.JSX.Element;
|
|
14
14
|
export {};
|
|
@@ -2,4 +2,4 @@ export interface GradeTableLoaderProps {
|
|
|
2
2
|
rowCount?: number;
|
|
3
3
|
showToolbar?: boolean;
|
|
4
4
|
}
|
|
5
|
-
export declare function GradeTableLoader({ rowCount, showToolbar, }: GradeTableLoaderProps): import("react
|
|
5
|
+
export declare function GradeTableLoader({ rowCount, showToolbar, }: GradeTableLoaderProps): import("react").JSX.Element;
|
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { DataTableLayoutProps } from "../type";
|
|
3
|
+
export declare function DataTable<T>({ data, columns, extraTools }: DataTableLayoutProps<T>): React.JSX.Element;
|
|
@@ -1,68 +1,304 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
import React, { useState } from "react";
|
|
4
|
-
import {
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import React, { useState, useEffect } from "react";
|
|
4
|
+
import { useReactTable, getCoreRowModel, getPaginationRowModel, getFilteredRowModel, getSortedRowModel, getGroupedRowModel, getExpandedRowModel, flexRender, } from "@tanstack/react-table";
|
|
5
|
+
import * as XLSX from "xlsx";
|
|
6
|
+
import { useSearchParams, useRouter, usePathname } from "next/navigation";
|
|
7
|
+
import { ChevronDown, ChevronRight, ChevronUp, Download, GripVertical, LayoutGrid, List, X } from "lucide-react";
|
|
8
|
+
import { Table, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, } from "../../../shadcn/table";
|
|
5
9
|
import { Badge } from "../../../shadcn/badge";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
import { Reload } from "../../reload-component";
|
|
11
|
+
import { DataTableSearch } from "../DataTableSearch";
|
|
12
|
+
import { DataTablePageSize } from "../DataTablePageSize";
|
|
13
|
+
import { DataTablePagination } from "../DataTablePagination";
|
|
14
|
+
import { DataTableFilter, FilterTagSpacer } from "../DataTableFilter";
|
|
15
|
+
import { DataTableColumns } from "../DataTableColumn";
|
|
16
|
+
import { Button } from "../../../shadcn/button";
|
|
17
|
+
import { ActionMenu } from "../../../ikoncomponents/action-menu";
|
|
18
|
+
// Assuming your converted components are in the same dire
|
|
19
|
+
/** Aggregate a single column's numeric values across the given rows. */
|
|
20
|
+
function aggregateRows(rows, key, type) {
|
|
21
|
+
if (type === "count")
|
|
22
|
+
return rows.length;
|
|
23
|
+
const values = rows.map((r) => { var _a; return Number((_a = r.original) === null || _a === void 0 ? void 0 : _a[key]) || 0; });
|
|
24
|
+
if (!values.length)
|
|
25
|
+
return 0;
|
|
26
|
+
switch (type) {
|
|
27
|
+
case "sum":
|
|
28
|
+
return values.reduce((a, b) => a + b, 0);
|
|
29
|
+
case "avg":
|
|
30
|
+
return values.reduce((a, b) => a + b, 0) / values.length;
|
|
31
|
+
case "min":
|
|
32
|
+
return Math.min(...values);
|
|
33
|
+
case "max":
|
|
34
|
+
return Math.max(...values);
|
|
35
|
+
default:
|
|
36
|
+
return 0;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/** Combine the sums of several columns left-to-right with an arithmetic operation. */
|
|
40
|
+
function combineColumns(rows, keys, op) {
|
|
41
|
+
const sums = keys.map((k) => aggregateRows(rows, k, "sum"));
|
|
42
|
+
return sums.reduce((acc, val, i) => {
|
|
43
|
+
if (i === 0)
|
|
44
|
+
return val;
|
|
45
|
+
switch (op) {
|
|
46
|
+
case "add":
|
|
47
|
+
return acc + val;
|
|
48
|
+
case "subtract":
|
|
49
|
+
return acc - val;
|
|
50
|
+
case "multiply":
|
|
51
|
+
return acc * val;
|
|
52
|
+
case "divide":
|
|
53
|
+
return val !== 0 ? acc / val : 0;
|
|
54
|
+
default:
|
|
55
|
+
return acc;
|
|
56
|
+
}
|
|
57
|
+
}, 0);
|
|
58
|
+
}
|
|
59
|
+
/** Resolve a footer cell definition to renderable content for the given column. */
|
|
60
|
+
function renderFooterCell(cell, rows, columnId) {
|
|
61
|
+
var _a, _b, _c, _d;
|
|
62
|
+
if (cell == null)
|
|
63
|
+
return null;
|
|
64
|
+
if (typeof cell === "string")
|
|
65
|
+
return cell;
|
|
66
|
+
if (cell.render)
|
|
67
|
+
return cell.render(rows.map((r) => r.original));
|
|
68
|
+
let value = null;
|
|
69
|
+
if (cell.operation && ((_a = cell.columns) === null || _a === void 0 ? void 0 : _a.length)) {
|
|
70
|
+
value = combineColumns(rows, cell.columns, cell.operation);
|
|
71
|
+
}
|
|
72
|
+
else if (cell.aggregate) {
|
|
73
|
+
value = aggregateRows(rows, (_b = cell.column) !== null && _b !== void 0 ? _b : columnId, cell.aggregate);
|
|
74
|
+
}
|
|
75
|
+
if (value == null)
|
|
76
|
+
return null;
|
|
77
|
+
const formatted = cell.decimals != null ? value.toFixed(cell.decimals) : value.toLocaleString();
|
|
78
|
+
return `${(_c = cell.prefix) !== null && _c !== void 0 ? _c : ""}${formatted}${(_d = cell.suffix) !== null && _d !== void 0 ? _d : ""}`;
|
|
79
|
+
}
|
|
80
|
+
export function DataTable({ data, columns, extraTools }) {
|
|
81
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
82
|
+
const [viewMode, setViewMode] = useState("list");
|
|
83
|
+
const router = useRouter();
|
|
84
|
+
const pathname = usePathname();
|
|
85
|
+
const searchParams = useSearchParams();
|
|
86
|
+
// 1. Sync State from URL
|
|
87
|
+
const pageIndex = Number(searchParams.get("page") || "1") - 1;
|
|
88
|
+
const [pagination, setPagination] = React.useState({
|
|
89
|
+
pageIndex: (_a = extraTools === null || extraTools === void 0 ? void 0 : extraTools.pageIndex) !== null && _a !== void 0 ? _a : 0,
|
|
90
|
+
pageSize: (_b = extraTools === null || extraTools === void 0 ? void 0 : extraTools.pageSize) !== null && _b !== void 0 ? _b : 10,
|
|
91
|
+
});
|
|
92
|
+
const [globalFilter, setGlobalFilter] = React.useState("");
|
|
93
|
+
// 2. Internal UI States (Sorting, Grouping, Expanded)
|
|
94
|
+
const [sorting, setSorting] = useState([]);
|
|
95
|
+
const [grouping, setGrouping] = useState((extraTools === null || extraTools === void 0 ? void 0 : extraTools.grouping) ? (_c = extraTools === null || extraTools === void 0 ? void 0 : extraTools.groupedValue) !== null && _c !== void 0 ? _c : [] : []);
|
|
96
|
+
const [expanded, setExpanded] = useState({});
|
|
97
|
+
const [rowSelection, setRowSelection] = useState({});
|
|
98
|
+
const [columnVisibility, setColumnVisibility] = useState({});
|
|
99
|
+
const [columnFilters, setColumnFilters] = useState([]);
|
|
100
|
+
const hiddenColumns = (extraTools === null || extraTools === void 0 ? void 0 : extraTools.hiddenColumns) || [];
|
|
101
|
+
for (const col of columns) {
|
|
102
|
+
if (col.filterFn === undefined) {
|
|
103
|
+
col.filterFn = "multiSelect"; // Set default filter function to "multiSelect" if not provided
|
|
104
|
+
// Make columns draggable by default
|
|
12
105
|
}
|
|
13
|
-
|
|
14
|
-
|
|
106
|
+
if (col.draggable === undefined) {
|
|
107
|
+
col["draggable"] = true;
|
|
15
108
|
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
109
|
+
}
|
|
110
|
+
if ((extraTools === null || extraTools === void 0 ? void 0 : extraTools.actionMenu) || (extraTools === null || extraTools === void 0 ? void 0 : extraTools.groupActionMenu)) {
|
|
111
|
+
columns.push({
|
|
112
|
+
id: "DTActions",
|
|
113
|
+
accessorKey: "Actions",
|
|
114
|
+
header: () => _jsx("div", { className: "text-center", children: "Action" }),
|
|
115
|
+
size: 20,
|
|
116
|
+
headerClassName: "text-center",
|
|
117
|
+
cell: ({ row }) => {
|
|
118
|
+
if (row.getIsGrouped()) {
|
|
119
|
+
return (extraTools === null || extraTools === void 0 ? void 0 : extraTools.groupActionMenu) ? (_jsx("div", { className: "text-end", children: _jsx(ActionMenu, { actionMenus: extraTools.groupActionMenu.items, extraActionParams: {
|
|
120
|
+
arguments: [
|
|
121
|
+
row.original,
|
|
122
|
+
...(extraTools.groupActionMenu.extraArguments || []),
|
|
123
|
+
],
|
|
124
|
+
} }) })) : null;
|
|
125
|
+
}
|
|
126
|
+
else if (extraTools === null || extraTools === void 0 ? void 0 : extraTools.actionMenu) {
|
|
127
|
+
return (_jsx("div", { className: "text-center", children: _jsx(ActionMenu, { actionMenus: extraTools.actionMenu.items, extraActionParams: {
|
|
128
|
+
arguments: [
|
|
129
|
+
row.original,
|
|
130
|
+
...(extraTools.actionMenu.extraArguments || []),
|
|
131
|
+
],
|
|
132
|
+
} }) }));
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
enableSorting: false,
|
|
139
|
+
enableHiding: false,
|
|
38
140
|
});
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
141
|
+
}
|
|
142
|
+
// 3. Configure Table
|
|
143
|
+
const table = useReactTable({
|
|
144
|
+
data,
|
|
145
|
+
columns,
|
|
146
|
+
pageCount: extraTools === null || extraTools === void 0 ? void 0 : extraTools.totalPages,
|
|
147
|
+
meta: {
|
|
148
|
+
footerLabel: extraTools === null || extraTools === void 0 ? void 0 : extraTools.footerLabel,
|
|
149
|
+
},
|
|
150
|
+
state: {
|
|
151
|
+
pagination: pagination,
|
|
152
|
+
globalFilter,
|
|
153
|
+
sorting,
|
|
154
|
+
grouping,
|
|
155
|
+
expanded,
|
|
156
|
+
rowSelection,
|
|
157
|
+
columnVisibility,
|
|
158
|
+
columnFilters
|
|
159
|
+
},
|
|
160
|
+
onSortingChange: setSorting,
|
|
161
|
+
onGroupingChange: setGrouping,
|
|
162
|
+
onExpandedChange: setExpanded,
|
|
163
|
+
onRowSelectionChange: setRowSelection,
|
|
164
|
+
onGlobalFilterChange: setGlobalFilter,
|
|
165
|
+
onPaginationChange: setPagination,
|
|
166
|
+
onColumnVisibilityChange: setColumnVisibility,
|
|
167
|
+
onColumnFiltersChange: setColumnFilters,
|
|
168
|
+
// Manual Mode for Server-Side Logic (URL-Driven)
|
|
169
|
+
// When true, the parent supplies already-paged `data` + `totalPages` and the
|
|
170
|
+
// table won't slice; when false/undefined it paginates the full data client-side.
|
|
171
|
+
manualPagination: (_d = extraTools === null || extraTools === void 0 ? void 0 : extraTools.manualPagination) !== null && _d !== void 0 ? _d : false,
|
|
172
|
+
manualFiltering: false,
|
|
173
|
+
getCoreRowModel: getCoreRowModel(),
|
|
174
|
+
getPaginationRowModel: getPaginationRowModel(),
|
|
175
|
+
getSortedRowModel: getSortedRowModel(),
|
|
176
|
+
getFilteredRowModel: getFilteredRowModel(),
|
|
177
|
+
getGroupedRowModel: getGroupedRowModel(),
|
|
178
|
+
getExpandedRowModel: getExpandedRowModel(),
|
|
179
|
+
filterFns: {
|
|
180
|
+
// Custom filter to check if row value exists in selected array
|
|
181
|
+
multiSelect: (row, columnId, filterValue) => {
|
|
182
|
+
if (!filterValue.length)
|
|
183
|
+
return true;
|
|
184
|
+
return filterValue.includes(String(row.getValue(columnId)));
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
});
|
|
188
|
+
useEffect(() => {
|
|
189
|
+
table.getAllLeafColumns().map((column) => {
|
|
190
|
+
if (hiddenColumns === null || hiddenColumns === void 0 ? void 0 : hiddenColumns.includes(column.id)) {
|
|
191
|
+
column.toggleVisibility(false);
|
|
54
192
|
}
|
|
55
|
-
return (_jsx(TableRow, { onClick: () => onRowClick && onRowClick(item), className: `hover:bg-muted/50 transition-colors border-b border-border ${onRowClick ? "cursor-pointer" : ""}`, children: columns.map((col, colIndex) => (_jsx(TableCell, { className: colIndex === 0 ? "font-medium" : "", style: { paddingLeft: colIndex === 0 ? `${level * 24 + 16}px` : undefined }, children: col.cell
|
|
56
|
-
? col.cell(item)
|
|
57
|
-
: col.accessorKey
|
|
58
|
-
? String(item[col.accessorKey] || "N/A")
|
|
59
|
-
: null }, colIndex))) }, keyExtractor(item)));
|
|
60
193
|
});
|
|
194
|
+
}, [hiddenColumns, table]);
|
|
195
|
+
// 4. Drag & Drop Logic for Grouping (from your code)
|
|
196
|
+
const handleDragStart = (e, headerId) => {
|
|
197
|
+
e.dataTransfer.setData("headerId", headerId);
|
|
198
|
+
};
|
|
199
|
+
const handleDrop = (e) => {
|
|
200
|
+
var _a, _b;
|
|
201
|
+
e.preventDefault();
|
|
202
|
+
const headerId = e.dataTransfer.getData("headerId");
|
|
203
|
+
if (headerId && !grouping.includes(headerId) && ((_a = table.getColumn(headerId)) === null || _a === void 0 ? void 0 : _a.getCanGroup())) {
|
|
204
|
+
(_b = table.getColumn(headerId)) === null || _b === void 0 ? void 0 : _b.toggleGrouping();
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
useEffect(() => {
|
|
208
|
+
// Sync globalFilter to URL when it changes
|
|
209
|
+
table.setGlobalFilter(searchParams.get("search") || "");
|
|
210
|
+
}, [searchParams, router, pathname]);
|
|
211
|
+
useEffect(() => {
|
|
212
|
+
var _a;
|
|
213
|
+
table.setPageSize(Number(searchParams.get("size") || (extraTools === null || extraTools === void 0 ? void 0 : extraTools.pageSize) || 10));
|
|
214
|
+
table.setPageIndex(Number(searchParams.get("page") || ((_a = extraTools === null || extraTools === void 0 ? void 0 : extraTools.pageIndex) !== null && _a !== void 0 ? _a : 0) + 1) - 1);
|
|
215
|
+
}, [searchParams, router, pathname]);
|
|
216
|
+
// Notify the parent on page / page-size change so it can fetch from its API
|
|
217
|
+
// (server-side / pageable mode). Harmless in client-side "all data" mode.
|
|
218
|
+
useEffect(() => {
|
|
219
|
+
var _a;
|
|
220
|
+
(_a = extraTools === null || extraTools === void 0 ? void 0 : extraTools.onPaginationChange) === null || _a === void 0 ? void 0 : _a.call(extraTools, pagination);
|
|
221
|
+
}, [pagination.pageIndex, pagination.pageSize]);
|
|
222
|
+
const handleExport = () => {
|
|
223
|
+
// 1. Get only the columns that are currently visible in the UI
|
|
224
|
+
const visibleColumns = table.getVisibleLeafColumns()
|
|
225
|
+
.filter(col => col.id !== "select" && col.id !== "actions");
|
|
226
|
+
// --- RECURSIVE FUNCTION ---
|
|
227
|
+
const processRows = (rows, level = 0) => {
|
|
228
|
+
return rows.flatMap((row) => {
|
|
229
|
+
if (row.getIsGrouped()) {
|
|
230
|
+
// 1. This is a Group Header Row
|
|
231
|
+
const groupValue = String(row.id.replaceAll(`${visibleColumns[0].id}:`, "")).trim() === "" || row.id.replaceAll(`${row.parentId ? `${row.parentId}>` : ``}`, "").replaceAll(`${row.groupingColumnId}>`, "").replaceAll(`${visibleColumns[0].id}:`, "").trim() === undefined ? "N/A" : row.id.replaceAll(`${row.parentId ? `${row.parentId}>` : ``}`, "").replaceAll(`${visibleColumns[0].id}:`, "").trim();
|
|
232
|
+
// Create the header row. We indent the text based on level for visual clarity in Excel.
|
|
233
|
+
const headerRow = {
|
|
234
|
+
[visibleColumns[0].id]: `${" ".repeat(level)} ${groupValue} (${row.subRows.length})`
|
|
235
|
+
};
|
|
236
|
+
// 2. Recursively process the subRows (could be more groups or final data)
|
|
237
|
+
return [headerRow, ...processRows(row.subRows, level + 1)];
|
|
238
|
+
}
|
|
239
|
+
else {
|
|
240
|
+
// 3. This is an actual Data Row (Leaf)
|
|
241
|
+
const rowData = {};
|
|
242
|
+
visibleColumns.forEach((col) => {
|
|
243
|
+
// Add indentation to the first column to show it belongs to the group above
|
|
244
|
+
const value = row.getValue(col.id);
|
|
245
|
+
rowData[col.id] = (col.id === visibleColumns[0].id) || (value === "Actions" || value === "actions")
|
|
246
|
+
? " " // + (value ?? "")
|
|
247
|
+
: value === undefined ? "N/A" : value; // Handle empty/undefined values
|
|
248
|
+
});
|
|
249
|
+
return [rowData];
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
};
|
|
253
|
+
// Decide which model to use based on your checkGrouping state
|
|
254
|
+
const finalData = table.getState().grouping.length > 0
|
|
255
|
+
? processRows(table.getGroupedRowModel().rows)
|
|
256
|
+
: table.getFilteredRowModel().rows.map(row => {
|
|
257
|
+
const rowData = {};
|
|
258
|
+
visibleColumns.forEach(col => rowData[col.id] = row.getValue(col.id));
|
|
259
|
+
return rowData;
|
|
260
|
+
});
|
|
261
|
+
// 3. Create and download
|
|
262
|
+
const worksheet = XLSX.utils.json_to_sheet(finalData);
|
|
263
|
+
// 4. --- AUTO-SIZE COLUMN WIDTH LOGIC ---
|
|
264
|
+
const colWidths = visibleColumns.map((col) => {
|
|
265
|
+
const header = typeof col.columnDef.header === "string" ? col.columnDef.header : col.id;
|
|
266
|
+
// Find the longest string in this column (header vs all row values)
|
|
267
|
+
const maxCharLength = Math.max(header.length, ...finalData.map((row) => String(row[header]).length));
|
|
268
|
+
// Set width (adding 2 or 3 for extra padding/breathing room)
|
|
269
|
+
return { wch: maxCharLength + 3 };
|
|
270
|
+
});
|
|
271
|
+
worksheet["!cols"] = colWidths;
|
|
272
|
+
const workbook = XLSX.utils.book_new();
|
|
273
|
+
XLSX.utils.book_append_sheet(workbook, worksheet, "Data");
|
|
274
|
+
XLSX.writeFile(workbook, `${extraTools === null || extraTools === void 0 ? void 0 : extraTools.fileName}.xlsx`);
|
|
61
275
|
};
|
|
62
|
-
return (
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
276
|
+
return (_jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "flex flex-col sm:flex-row items-center justify-between gap-4 w-full", children: [_jsx("div", { className: "flex items-center gap-2 w-full sm:w-auto sm:max-w-[200px] shrink-0", children: _jsx(DataTableSearch, {}) }), _jsxs("div", { className: "flex items-center gap-3 flex-wrap shrink-0", children: [(extraTools === null || extraTools === void 0 ? void 0 : extraTools.actionNode) && (extraTools === null || extraTools === void 0 ? void 0 : extraTools.actionNode), (viewMode === "list") &&
|
|
277
|
+
(_jsxs(_Fragment, { children: [_jsx(DataTableFilter, { table: table }), _jsx(DataTableColumns, { table: table }), _jsx(Button, { variant: "outline", size: "sm", className: "h-9 gap-2 border-border bg-background", onClick: () => handleExport(), children: _jsx(Download, { className: "w-4 h-4" }) })] })), (extraTools === null || extraTools === void 0 ? void 0 : extraTools.toggleViewMode) && (_jsxs("div", { className: "flex items-center border border-border rounded-md bg-background overflow-hidden h-9", children: [_jsx("button", { onClick: () => setViewMode("list"), className: `px-2.5 h-full flex items-center justify-center transition-colors ${viewMode === "list" ? "bg-muted text-foreground" : "text-muted-foreground hover:bg-muted/50"}`, title: "List View", children: _jsx(List, { className: "w-4 h-4" }) }), _jsx("button", { onClick: () => setViewMode("grid"), className: `px-2.5 h-full flex items-center justify-center transition-colors ${viewMode === "grid" ? "bg-muted text-foreground" : "text-muted-foreground hover:bg-muted/50"}`, title: "Grid View", children: _jsx(LayoutGrid, { className: "w-4 h-4" }) })] }))] })] }), _jsx(FilterTagSpacer, { activeFilters: table.getState().columnFilters, table: table }), (viewMode === "list" && ((extraTools === null || extraTools === void 0 ? void 0 : extraTools.grouping) || (extraTools === null || extraTools === void 0 ? void 0 : extraTools.grouping) === undefined)) &&
|
|
278
|
+
(_jsx(_Fragment, { children: _jsxs("div", { className: "w-full flex items-center gap-2 p-2 border border-dashed border-border rounded-lg bg-muted/20 min-h-[48px] transition-all hover:bg-muted/40 group shadow-sm", onDragOver: (e) => e.preventDefault(), onDrop: handleDrop, children: [_jsxs("div", { className: "flex items-center gap-2 text-muted-foreground text-xs px-2 select-none border-r pr-4 mr-2 border-border/50", children: [_jsx(GripVertical, { className: "w-4 h-4 opacity-40" }), _jsx("span", { className: "font-semibold uppercase tracking-wider opacity-70", children: "Grouping" })] }), _jsx("div", { className: "flex flex-wrap gap-2", children: grouping.length === 0 ? (_jsx("div", { className: "flex items-center gap-2 text-muted-foreground/60 text-sm italic py-1", children: _jsx("span", { children: "Drag column headers here to group your data..." }) })) : (grouping.map((gid) => {
|
|
279
|
+
var _a;
|
|
280
|
+
const headerDef = (_a = table.getColumn(gid)) === null || _a === void 0 ? void 0 : _a.columnDef.header;
|
|
281
|
+
const label = typeof headerDef === "string" ? headerDef : gid;
|
|
282
|
+
return (_jsxs(Badge, { variant: "secondary", className: "gap-2 pl-3 pr-1.5 h-8 text-xs font-semibold bg-background border shadow-sm animate-in fade-in zoom-in duration-200", children: [label, _jsx("button", { onClick: () => { var _a; return (_a = table.getColumn(gid)) === null || _a === void 0 ? void 0 : _a.toggleGrouping(); }, className: "hover:bg-muted rounded-full p-0.5 transition-colors", children: _jsx(X, { className: "w-3.5 h-3.5" }) })] }, gid));
|
|
283
|
+
})) })] }) })), _jsxs("div", { className: "relative min-h-[300px] mt-2", children: [_jsx(Reload, { isLoading: (_e = extraTools === null || extraTools === void 0 ? void 0 : extraTools.isLoading) !== null && _e !== void 0 ? _e : false, onReload: (extraTools === null || extraTools === void 0 ? void 0 : extraTools.onReload) || (() => window.location.reload()) }), _jsx("div", { className: `transition-all duration-300 ${(extraTools === null || extraTools === void 0 ? void 0 : extraTools.isLoading) ? "opacity-50 pointer-events-none" : ""}`, children: viewMode === "list" ? (_jsx("div", { className: "rounded-md border bg-background shadow-sm overflow-hidden", children: _jsx("div", { className: "overflow-auto", style: { maxHeight: (_f = extraTools === null || extraTools === void 0 ? void 0 : extraTools.tableHeight) !== null && _f !== void 0 ? _f : "500px" }, children: _jsxs(Table, { children: [_jsx(TableHeader, { className: "sticky top-0 z-10", children: table.getHeaderGroups().map((headerGroup) => (_jsx(TableRow, { className: "bg-muted border-b border-border", children: headerGroup.headers.map((header) => {
|
|
284
|
+
var _a, _b;
|
|
285
|
+
return (_jsx(TableHead, { className: `font-semibold text-muted-foreground group relative ${(_a = header.column.columnDef.headerClassName) !== null && _a !== void 0 ? _a : ""}`, children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: "cursor-grab active:cursor-grabbing p-1 hover:bg-background/50 rounded transition-colors", draggable: true, onDragStart: (e) => handleDragStart(e, header.id), children: _jsx(GripVertical, { className: "w-3 h-3 opacity-0 group-hover:opacity-100 transition-opacity" }) }), _jsxs("div", { className: "flex items-center gap-2 cursor-pointer select-none", onClick: header.column.getToggleSortingHandler(), children: [flexRender(header.column.columnDef.header, header.getContext()), (_b = {
|
|
286
|
+
asc: _jsx(ChevronUp, { size: 14 }),
|
|
287
|
+
desc: _jsx(ChevronDown, { size: 14 }),
|
|
288
|
+
}[header.column.getIsSorted()]) !== null && _b !== void 0 ? _b : null] })] }) }, header.id));
|
|
289
|
+
}) }, headerGroup.id))) }), _jsx(TableBody, { children: table.getRowModel().rows.length > 0 ? (table.getRowModel().rows.map((row) => (_jsx(TableRow, { className: `hover:bg-muted/50 transition-colors border-b border-border ${row.getIsGrouped() ? "bg-muted/40 hover:bg-muted/60 cursor-pointer border-l-4 border-l-primary/50" : ""} ${row.getIsSelected() ? "bg-accent/20" : ""}`, children: row.getVisibleCells().map((cell) => {
|
|
290
|
+
var _a;
|
|
291
|
+
return (_jsx(TableCell, { children: cell.getIsGrouped() ? (_jsxs("button", { onClick: row.getToggleExpandedHandler(), className: "flex items-center gap-2 font-semibold", children: [row.getIsExpanded() ? _jsx(ChevronDown, { size: 16 }) : _jsx(ChevronRight, { size: 16 }), flexRender(cell.column.columnDef.cell, cell.getContext()), _jsxs(Badge, { variant: "outline", className: "ml-2 text-[10px] py-0 h-4", children: [row.subRows.length, " items"] })] })) : cell.getIsAggregated() ? (flexRender((_a = cell.column.columnDef.aggregatedCell) !== null && _a !== void 0 ? _a : cell.column.columnDef.cell, cell.getContext())) : cell.getIsPlaceholder() ? null : (flexRender(cell.column.columnDef.cell, cell.getContext())) }, cell.id));
|
|
292
|
+
}) }, row.id)))) : (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: table.getVisibleLeafColumns().length, className: "h-24 text-center text-muted-foreground", children: "No records found." }) })) }), (extraTools === null || extraTools === void 0 ? void 0 : extraTools.footerRows) && extraTools.footerRows.length > 0 ? (
|
|
293
|
+
// Dynamic footer: one row per config entry, cells keyed by column id.
|
|
294
|
+
_jsx(TableFooter, { className: "sticky bottom-0 z-10 bg-muted/30 border-t-2 border-border font-bold", children: extraTools.footerRows.map((footerRow, rowIndex) => (_jsx(TableRow, { className: footerRow.className, children: table.getVisibleLeafColumns().map((column) => {
|
|
295
|
+
var _a;
|
|
296
|
+
const cellConfig = (_a = footerRow.cells) === null || _a === void 0 ? void 0 : _a[column.id];
|
|
297
|
+
const cellClassName = cellConfig && typeof cellConfig === "object"
|
|
298
|
+
? cellConfig.className
|
|
299
|
+
: undefined;
|
|
300
|
+
return (_jsx(TableCell, { className: `text-left ${cellClassName !== null && cellClassName !== void 0 ? cellClassName : ""}`, children: renderFooterCell(cellConfig, table.getFilteredRowModel().rows, column.id) }, column.id));
|
|
301
|
+
}) }, rowIndex))) })) : ((extraTools === null || extraTools === void 0 ? void 0 : extraTools.showFooter) && (_jsx(TableFooter, { className: "bg-muted/30 border-t-2 border-border font-bold", children: table.getFooterGroups().map((footerGroup) => (_jsx(TableRow, { children: footerGroup.headers.map((header) => (_jsx(TableCell, { className: "text-left", children: header.isPlaceholder
|
|
302
|
+
? null
|
|
303
|
+
: flexRender(header.column.columnDef.footer, header.getContext()) }, header.id))) }, footerGroup.id))) })))] }) }) })) : (extraTools === null || extraTools === void 0 ? void 0 : extraTools.gridComponent) ? (_jsx("div", { className: "overflow-auto", style: { maxHeight: (_g = extraTools === null || extraTools === void 0 ? void 0 : extraTools.tableHeight) !== null && _g !== void 0 ? _g : "500px" }, children: extraTools.gridComponent(table.getFilteredRowModel().rows.map((row) => row.original)) })) : (_jsx("div", { className: "p-12 text-center text-muted-foreground border border-border border-dashed rounded-md bg-muted/20", children: "Grid view not implemented for this component yet." })) })] }), viewMode === "list" && (_jsxs("div", { className: "flex flex-col sm:flex-row items-center justify-between gap-4 pt-4 border-t border-border mt-4", children: [_jsx(DataTablePageSize, {}), _jsx(DataTablePagination, { totalPages: (_h = extraTools === null || extraTools === void 0 ? void 0 : extraTools.totalPages) !== null && _h !== void 0 ? _h : Math.ceil(data.length / (pagination.pageSize || 10)), currentPage: pageIndex + 1 })] }))] }));
|
|
68
304
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Settings2, Check } from "lucide-react";
|
|
4
|
+
import { Button } from "../../../shadcn/button";
|
|
5
|
+
import { DropdownMenu, DropdownMenuContent, DropdownMenuTrigger } from "../../../shadcn/dropdown-menu";
|
|
6
|
+
export function DataTableColumns({ table }) {
|
|
7
|
+
return (_jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsxs(Button, { variant: "outline", size: "sm", className: "h-9 gap-2 border-border bg-background", children: [_jsx(Settings2, { className: "w-4 h-4" }), "Columns"] }) }), _jsxs(DropdownMenuContent, { align: "end", className: "w-48 p-2", children: [_jsx("div", { className: "px-2 py-1.5 text-xs font-semibold text-muted-foreground uppercase tracking-wider", children: "Toggle Columns" }), table.getAllLeafColumns().map((column) => {
|
|
8
|
+
// Skip columns that don't have an ID or are special (like selection)
|
|
9
|
+
if (!column.getCanHide())
|
|
10
|
+
return null;
|
|
11
|
+
const headerText = typeof column.columnDef.header === "string"
|
|
12
|
+
? column.columnDef.header
|
|
13
|
+
: column.id;
|
|
14
|
+
const isVisible = column.getIsVisible();
|
|
15
|
+
return (_jsxs("button", { onClick: () => column.toggleVisibility(!isVisible), className: "flex w-full items-center gap-2 px-2 py-1.5 text-sm rounded-sm hover:bg-muted transition-colors capitalize", children: [_jsx("div", { className: `flex h-4 w-4 items-center justify-center rounded-sm border border-primary ${isVisible ? "bg-primary text-primary-foreground" : "bg-transparent"}`, children: isVisible && _jsx(Check, { className: "h-3 w-3" }) }), _jsx("span", { className: "truncate", children: headerText })] }, column.id));
|
|
16
|
+
})] })] }));
|
|
17
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState, useMemo } from "react";
|
|
4
|
+
import { X, ChevronDown, Check, RotateCcw, Search, ListFilter } from "lucide-react";
|
|
5
|
+
import { DropdownMenu, DropdownMenuContent, DropdownMenuTrigger, } from "../../../shadcn/dropdown-menu";
|
|
6
|
+
import { Button } from "../../../shadcn/button";
|
|
7
|
+
export function DataTableFilter({ table }) {
|
|
8
|
+
const [open, setOpen] = useState(false);
|
|
9
|
+
const [searchQuery, setSearchQuery] = useState("");
|
|
10
|
+
const [pendingColumns, setPendingColumns] = useState([]);
|
|
11
|
+
// Syncing with Table State: Which columns currently have a filter active?
|
|
12
|
+
const activeFilters = table.getState().columnFilters;
|
|
13
|
+
const activeIds = activeFilters.map((f) => f.id);
|
|
14
|
+
const columns = table.getAllLeafColumns().filter((col) => col.getCanFilter());
|
|
15
|
+
const filteredColumns = columns.filter((col) => {
|
|
16
|
+
if (col.id === "DTActions")
|
|
17
|
+
return false; // Exclude action column from filter list
|
|
18
|
+
const label = (typeof col.columnDef.header === "string") ? col.columnDef.header : col.id;
|
|
19
|
+
return label.toLowerCase().includes(searchQuery.toLowerCase());
|
|
20
|
+
});
|
|
21
|
+
const togglePendingColumn = (id) => {
|
|
22
|
+
setPendingColumns((prev) => prev.includes(id) ? prev.filter((c) => c !== id) : [...prev, id]);
|
|
23
|
+
};
|
|
24
|
+
return (_jsxs(DropdownMenu, { open: open, onOpenChange: (o) => {
|
|
25
|
+
setOpen(o);
|
|
26
|
+
if (o)
|
|
27
|
+
setPendingColumns(activeIds);
|
|
28
|
+
}, children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsxs(Button, { variant: "outline", size: "sm", className: "h-9 gap-2 border-border bg-background relative", children: [_jsx(ListFilter, { className: "w-4 h-4" }), "Filter", activeIds.length > 0 && (_jsx("span", { className: "absolute -top-1 -right-1 w-4 h-4 bg-foreground text-background text-[10px] rounded-full flex items-center justify-center font-bold", children: activeIds.length }))] }) }), _jsxs(DropdownMenuContent, { align: "end", className: "w-56 p-2 space-y-2", children: [_jsx("div", { className: "px-2 py-1.5 text-xs font-semibold text-muted-foreground uppercase tracking-wider", children: "Filter" }), _jsxs("div", { className: "px-2 relative", children: [_jsx(Search, { className: "absolute left-4 top-1/2 -translate-y-1/2 w-3.5 h-3.5 text-muted-foreground" }), _jsx("input", { type: "text", placeholder: "Search columns...", value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), className: "w-full h-8 pl-8 pr-2 text-xs rounded-md border border-border bg-muted/20 focus:outline-none focus:ring-1 focus:ring-foreground/30" })] }), _jsx("div", { className: "space-y-1 max-h-[300px] overflow-y-auto pr-1", children: filteredColumns.map((col) => {
|
|
29
|
+
const label = typeof col.columnDef.header === "string"
|
|
30
|
+
? col.columnDef.header
|
|
31
|
+
: col.id;
|
|
32
|
+
const isSelected = pendingColumns.includes(col.id);
|
|
33
|
+
return (_jsxs("button", { onClick: () => togglePendingColumn(col.id), className: "flex w-full items-center gap-2 px-2 py-1.5 text-sm rounded-sm hover:bg-muted transition-colors", children: [_jsx("div", { className: "flex h-4 w-4 items-center justify-center rounded-sm border", style: isSelected
|
|
34
|
+
? { backgroundColor: "hsl(var(--foreground))", borderColor: "hsl(var(--foreground))", color: "hsl(var(--background))" }
|
|
35
|
+
: { borderColor: "hsl(var(--border))" }, children: isSelected && _jsx(Check, { className: "h-3 w-3" }) }), _jsx("span", { className: "truncate", children: label })] }, col.id));
|
|
36
|
+
}) }), _jsxs("div", { className: "px-2 pt-2 mt-1 flex gap-2", children: [_jsx(Button, { variant: "default", size: "sm", className: "flex-1 text-xs font-medium bg-foreground text-background hover:bg-foreground/90", onClick: () => {
|
|
37
|
+
columns.forEach((col) => {
|
|
38
|
+
const wasActive = activeIds.includes(col.id);
|
|
39
|
+
const willActive = pendingColumns.includes(col.id);
|
|
40
|
+
if (willActive && !wasActive)
|
|
41
|
+
col.setFilterValue([]);
|
|
42
|
+
if (!willActive && wasActive)
|
|
43
|
+
col.setFilterValue(undefined);
|
|
44
|
+
});
|
|
45
|
+
setOpen(false);
|
|
46
|
+
}, children: "Apply" }), _jsxs(Button, { variant: "secondary", size: "sm", className: "flex-1 text-xs font-medium bg-secondary hover:bg-secondary/80 text-secondary-foreground", onClick: () => {
|
|
47
|
+
setPendingColumns([]);
|
|
48
|
+
table.resetColumnFilters();
|
|
49
|
+
setOpen(false);
|
|
50
|
+
}, children: [_jsx(RotateCcw, { className: "w-3.5 h-3.5 mr-2 inline" }), " Reset"] })] })] })] }));
|
|
51
|
+
}
|
|
52
|
+
export function FilterTagSpacer({ activeFilters, table }) {
|
|
53
|
+
if (!activeFilters || activeFilters.length === 0)
|
|
54
|
+
return null;
|
|
55
|
+
return (
|
|
56
|
+
// {/* --- ACTIVE FILTER TAGS --- */}
|
|
57
|
+
_jsx("div", { className: "flex items-center gap-2 flex-1 min-w-0 overflow-x-auto", style: { scrollbarWidth: "none", msOverflowStyle: "none" }, children: activeFilters.map((filter) => (_jsx(FilterTag, { filter: filter, table: table }, filter.id))) }));
|
|
58
|
+
}
|
|
59
|
+
// --- INDIVIDUAL TAG COMPONENT WITH VALUE DROPDOWN ---
|
|
60
|
+
function FilterTag({ filter, table }) {
|
|
61
|
+
const [searchQuery, setSearchQuery] = useState("");
|
|
62
|
+
const column = table.getColumn(filter.id);
|
|
63
|
+
const colHeader = typeof (column === null || column === void 0 ? void 0 : column.columnDef.header) === "string" ? column.columnDef.header : filter.id;
|
|
64
|
+
const selectedValues = filter.value || [];
|
|
65
|
+
// Extract unique values from data
|
|
66
|
+
const uniqueValues = useMemo(() => {
|
|
67
|
+
const set = new Set();
|
|
68
|
+
table.getPreFilteredRowModel().flatRows.forEach((row) => {
|
|
69
|
+
const val = row.getValue(filter.id);
|
|
70
|
+
if (val !== null && val !== undefined)
|
|
71
|
+
set.add(val);
|
|
72
|
+
});
|
|
73
|
+
return Array.from(set).sort();
|
|
74
|
+
}, [table.getPreFilteredRowModel().flatRows, filter.id]);
|
|
75
|
+
const filteredValues = uniqueValues.filter((v) => String(v).toLowerCase().includes(searchQuery.toLowerCase()));
|
|
76
|
+
const toggleValue = (val) => {
|
|
77
|
+
const next = selectedValues.includes(val)
|
|
78
|
+
? selectedValues.filter((v) => v !== val)
|
|
79
|
+
: [...selectedValues, val];
|
|
80
|
+
column.setFilterValue(next);
|
|
81
|
+
};
|
|
82
|
+
return (_jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsxs("div", { className: "flex items-center gap-1.5 px-3 py-1.5 h-9 bg-muted/50 border border-border rounded-full text-xs font-medium cursor-pointer hover:bg-muted/80 transition-colors flex-1 shrink min-w-[140px] max-w-fit", title: `${colHeader}: ${selectedValues.length} Selected`, children: [_jsxs("span", { className: "uppercase truncate shrink font-semibold", children: [colHeader, ":"] }), _jsxs("span", { className: "text-muted-foreground whitespace-nowrap shrink-0", children: [selectedValues.length, " Selected"] }), _jsx(ChevronDown, { className: "w-3.5 h-3.5 ml-1 opacity-50 shrink-0" }), _jsx("div", { className: "p-0.5 ml-1 rounded-full hover:bg-background/80 shrink-0", onClick: (e) => {
|
|
83
|
+
e.preventDefault();
|
|
84
|
+
e.stopPropagation();
|
|
85
|
+
column.setFilterValue(undefined);
|
|
86
|
+
}, onPointerDown: (e) => {
|
|
87
|
+
e.stopPropagation();
|
|
88
|
+
}, children: _jsx(X, { className: "w-3.5 h-3.5" }) })] }) }), _jsxs(DropdownMenuContent, { align: "start", className: "w-56 p-2 space-y-2", children: [_jsxs("div", { className: "px-2 py-1.5 text-xs font-semibold text-muted-foreground uppercase tracking-wider", children: ["Filter ", colHeader] }), _jsxs("div", { className: "px-2 relative", children: [_jsx(Search, { className: "absolute left-4 top-1/2 -translate-y-1/2 w-3.5 h-3.5 text-muted-foreground" }), _jsx("input", { type: "text", placeholder: "Search items...", value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), className: "w-full h-8 pl-8 pr-2 text-xs rounded-md border border-border bg-muted/20 focus:outline-none focus:ring-1 focus:ring-foreground/30" })] }), _jsxs("div", { className: "space-y-1 max-h-[200px] overflow-y-auto pr-1", children: [filteredValues.map((val) => {
|
|
89
|
+
const isSelected = selectedValues.includes(val);
|
|
90
|
+
const label = String(val).trim() === "" ? "N/A" : String(val);
|
|
91
|
+
return (_jsxs("button", { onClick: () => toggleValue(val), className: "flex w-full items-center gap-2 px-2 py-1.5 text-sm rounded-sm hover:bg-muted transition-colors", children: [_jsx("div", { className: "flex h-4 w-4 items-center justify-center rounded-sm border", style: isSelected
|
|
92
|
+
? { backgroundColor: "hsl(var(--foreground))", borderColor: "hsl(var(--foreground))", color: "hsl(var(--background))" }
|
|
93
|
+
: { borderColor: "hsl(var(--border))" }, children: isSelected && _jsx(Check, { className: "h-3 w-3" }) }), _jsx("span", { className: "truncate text-left", children: label })] }, String(val)));
|
|
94
|
+
}), filteredValues.length === 0 && (_jsx("div", { className: "px-2 py-2 text-xs text-muted-foreground text-center", children: "No items found." }))] }), selectedValues.length > 0 && (_jsx("div", { className: "px-2 pt-1 border-t", children: _jsx(Button, { variant: "ghost", size: "sm", className: "w-full text-xs", onClick: () => column.setFilterValue([]), children: "Clear Selections" }) }))] })] }));
|
|
95
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare function DataTablePageSize(): import("react
|
|
1
|
+
export declare function DataTablePageSize(): import("react").JSX.Element;
|