@bilalsino/react-tanstack-data-table
Version:
Reusable React data table component with sorting, filtering, and pagination
1,390 lines (1,369 loc) • 64.6 kB
JavaScript
var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp.call(b, prop))
__defNormalProp(a, prop, b[prop]);
if (__getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(b)) {
if (__propIsEnum.call(b, prop))
__defNormalProp(a, prop, b[prop]);
}
return a;
};
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
var __objRest = (source, exclude) => {
var target = {};
for (var prop in source)
if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
target[prop] = source[prop];
if (source != null && __getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(source)) {
if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
target[prop] = source[prop];
}
return target;
};
// src/lib/stores/tableStore/index.ts
import { create } from "zustand";
import { devtools } from "zustand/middleware";
var useTableStore = create()(
devtools(
(set) => ({
tableData: [],
setTableData: (tableData) => set((state) => {
const existingTableIndex = state.tableData.findIndex(
(t) => t.tableId === tableData.tableId
);
if (existingTableIndex >= 0) {
const newTableData = [...state.tableData];
newTableData[existingTableIndex] = tableData;
return { tableData: newTableData };
}
return { tableData: [...state.tableData, tableData] };
}),
removeTableData: (tableId) => set((state) => ({
tableData: state.tableData.filter((t) => t.tableId !== tableId)
}))
}),
{ name: "table-storage" }
)
);
var tableStore_default = useTableStore;
// src/components/CustomTable/index.tsx
import {
flexRender,
getCoreRowModel,
getFacetedMinMaxValues,
getFacetedRowModel,
getFacetedUniqueValues,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
useReactTable
} from "@tanstack/react-table";
import { useEffect as useEffect2, useRef, useState as useState3, useMemo } from "react";
import { useVirtualizer } from "@tanstack/react-virtual";
import { AlertTriangle, ChevronUp, ChevronDown } from "lucide-react";
// src/lib/utils.ts
import { clsx } from "clsx";
import { twMerge } from "tailwind-merge";
function cn(...inputs) {
return twMerge(clsx(inputs));
}
var getCommonPinningStyles = (column) => {
const isPinned = column.getIsPinned();
const isLastLeftPinnedColumn = isPinned === "left" && column.getIsLastColumn("left");
const isFirstRightPinnedColumn = isPinned === "right" && column.getIsFirstColumn("right");
return {
/* boxShadow: isLastLeftPinnedColumn
? "-4px 0 4px -4px lightgray inset"
: isFirstRightPinnedColumn
? "4px 0 4px -4px lightgray inset"
: undefined, */
left: isPinned === "left" ? `${column.getStart("left")}px` : void 0,
right: isPinned === "right" ? `${column.getAfter("right")}px` : void 0,
position: isPinned ? "sticky" : "relative",
zIndex: isPinned ? 1 : 0
};
};
// src/components/Loading/Loading.tsx
import { jsx, jsxs } from "react/jsx-runtime";
var Loading = (_a) => {
var props = __objRest(_a, []);
return /* @__PURE__ */ jsxs(
"div",
__spreadProps(__spreadValues({
className: cn(
"absolute top-0 left-0 w-full h-full flex items-center justify-center space-x-2 bg-white/50 backdrop-blur-sm z-30",
props.className
)
}, props), {
children: [
/* @__PURE__ */ jsx("div", { className: "h-4 w-4 bg-zinc-800 rounded-full animate-bounce [animation-delay:-0.3s]" }),
/* @__PURE__ */ jsx("div", { className: "h-4 w-4 bg-zinc-800 rounded-full animate-bounce [animation-delay:-0.15s]" }),
/* @__PURE__ */ jsx("div", { className: "h-4 w-4 bg-zinc-800 rounded-full animate-bounce" })
]
})
);
};
// src/components/CustomTable/BulkActions.tsx
import { jsx as jsx2 } from "react/jsx-runtime";
var BulkActions = ({ children }) => {
return /* @__PURE__ */ jsx2("div", { className: "sticky flex items-center justify-center top-16 -translate-y-1/2 z-30", children: /* @__PURE__ */ jsx2("div", { className: "bg-white px-2 py-2 rounded-xl shadow-md flex items-center justify-center gap-2", children }) });
};
var BulkActions_default = BulkActions;
// src/components/CustomTable/Pagination.tsx
import React, { useEffect } from "react";
import { ChevronLeft, ChevronRight, List } from "lucide-react";
// src/components/ui/button.tsx
import { Slot } from "@radix-ui/react-slot";
import { cva } from "class-variance-authority";
import { jsx as jsx3 } from "react/jsx-runtime";
var buttonVariants = cva(
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
{
variants: {
variant: {
default: "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
destructive: "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
outline: "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
secondary: "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
link: "text-primary underline-offset-4 hover:underline"
},
size: {
default: "h-9 px-4 py-2 has-[>svg]:px-3",
sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
icon: "size-9"
}
},
defaultVariants: {
variant: "default",
size: "default"
}
}
);
function Button(_a) {
var _b = _a, {
className,
variant,
size,
asChild = false
} = _b, props = __objRest(_b, [
"className",
"variant",
"size",
"asChild"
]);
const Comp = asChild ? Slot : "button";
return /* @__PURE__ */ jsx3(
Comp,
__spreadValues({
"data-slot": "button",
className: cn(buttonVariants({ variant, size, className }))
}, props)
);
}
// src/components/ui/select.tsx
import * as SelectPrimitive from "@radix-ui/react-select";
import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react";
import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
function Select(_a) {
var props = __objRest(_a, []);
return /* @__PURE__ */ jsx4(SelectPrimitive.Root, __spreadValues({ "data-slot": "select" }, props));
}
function SelectGroup(_a) {
var props = __objRest(_a, []);
return /* @__PURE__ */ jsx4(SelectPrimitive.Group, __spreadValues({ "data-slot": "select-group" }, props));
}
function SelectValue(_a) {
var props = __objRest(_a, []);
return /* @__PURE__ */ jsx4(SelectPrimitive.Value, __spreadValues({ "data-slot": "select-value" }, props));
}
function SelectTrigger(_a) {
var _b = _a, {
className,
size = "default",
children
} = _b, props = __objRest(_b, [
"className",
"size",
"children"
]);
return /* @__PURE__ */ jsxs2(
SelectPrimitive.Trigger,
__spreadProps(__spreadValues({
"data-slot": "select-trigger",
"data-size": size,
className: cn(
"flex h-10 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background placeholder:text-zinc-600 focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
className
)
}, props), {
children: [
children,
/* @__PURE__ */ jsx4(SelectPrimitive.Icon, { asChild: true, children: /* @__PURE__ */ jsx4(ChevronDownIcon, { className: "size-4 opacity-50" }) })
]
})
);
}
function SelectContent(_a) {
var _b = _a, {
className,
children,
position = "popper"
} = _b, props = __objRest(_b, [
"className",
"children",
"position"
]);
return /* @__PURE__ */ jsx4(SelectPrimitive.Portal, { children: /* @__PURE__ */ jsxs2(
SelectPrimitive.Content,
__spreadProps(__spreadValues({
"data-slot": "select-content",
className: cn(
"relative z-[999999] max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-white text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
position === "popper" && "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
className
),
position
}, props), {
children: [
/* @__PURE__ */ jsx4(SelectScrollUpButton, {}),
/* @__PURE__ */ jsx4(
SelectPrimitive.Viewport,
{
className: cn(
"p-1",
position === "popper" && "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1"
),
children
}
),
/* @__PURE__ */ jsx4(SelectScrollDownButton, {})
]
})
) });
}
function SelectItem(_a) {
var _b = _a, {
className,
children
} = _b, props = __objRest(_b, [
"className",
"children"
]);
return /* @__PURE__ */ jsxs2(
SelectPrimitive.Item,
__spreadProps(__spreadValues({
"data-slot": "select-item",
className: cn(
"focus:bg-accent focus:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
className
)
}, props), {
children: [
/* @__PURE__ */ jsx4("span", { className: "absolute right-2 flex size-3.5 items-center justify-center", children: /* @__PURE__ */ jsx4(SelectPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx4(CheckIcon, { className: "size-4" }) }) }),
/* @__PURE__ */ jsx4(SelectPrimitive.ItemText, { children })
]
})
);
}
function SelectScrollUpButton(_a) {
var _b = _a, {
className
} = _b, props = __objRest(_b, [
"className"
]);
return /* @__PURE__ */ jsx4(
SelectPrimitive.ScrollUpButton,
__spreadProps(__spreadValues({
"data-slot": "select-scroll-up-button",
className: cn(
"flex cursor-default items-center justify-center py-1",
className
)
}, props), {
children: /* @__PURE__ */ jsx4(ChevronUpIcon, { className: "size-4" })
})
);
}
function SelectScrollDownButton(_a) {
var _b = _a, {
className
} = _b, props = __objRest(_b, [
"className"
]);
return /* @__PURE__ */ jsx4(
SelectPrimitive.ScrollDownButton,
__spreadProps(__spreadValues({
"data-slot": "select-scroll-down-button",
className: cn(
"flex cursor-default items-center justify-center py-1",
className
)
}, props), {
children: /* @__PURE__ */ jsx4(ChevronDownIcon, { className: "size-4" })
})
);
}
// src/components/FormComponents/FormSelect/FormSelect.tsx
import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
var FormSelect = (_a) => {
var _b = _a, {
label,
className,
options,
placeholder
} = _b, props = __objRest(_b, [
"label",
"className",
"options",
"placeholder"
]);
var _a2;
return /* @__PURE__ */ jsxs3("div", { children: [
label && /* @__PURE__ */ jsx5("div", { className: "text-sm font-medium text-zinc-800 mb-1 block", children: label }),
/* @__PURE__ */ jsx5("div", { className: cn("relative flex items-center", className), children: /* @__PURE__ */ jsxs3(
Select,
{
onValueChange: (value) => {
var _a3;
return (_a3 = props.onChange) == null ? void 0 : _a3.call(props, {
target: { value }
});
},
value: String((_a2 = props.value) != null ? _a2 : ""),
children: [
/* @__PURE__ */ jsx5(SelectTrigger, { children: /* @__PURE__ */ jsx5(SelectValue, { placeholder }) }),
/* @__PURE__ */ jsx5(SelectContent, { children: /* @__PURE__ */ jsx5(SelectGroup, { children: options == null ? void 0 : options.map((item) => /* @__PURE__ */ jsx5(SelectItem, { value: item.value, children: item.label }, item.value)) }) })
]
}
) })
] });
};
FormSelect.displayName = "FormSelect";
// src/components/CustomTable/Pagination.tsx
import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
var Pagination = ({
table,
setPagination,
pagination,
rows,
manualPagination,
loading,
hidePageSize,
showTotalCount
}) => {
var _a, _b, _c, _d, _e;
const [lastValues, setLastValues] = React.useState({
pageSize: 0,
currentPage: 0,
totalPages: 0,
rowCount: 0
});
const pageSize = table ? table.getState().pagination.pageSize : pagination.pageSize;
const currentPage = table ? table.getState().pagination.pageIndex + 1 : pagination.pageIndex + 1;
const totalPages = table ? table.getPageCount() : Math.ceil(((_a = rows == null ? void 0 : rows.rowCount) != null ? _a : 0) / pageSize);
useEffect(() => {
if (!loading && (rows == null ? void 0 : rows.rowCount)) {
setLastValues({
pageSize,
currentPage,
totalPages,
rowCount: rows == null ? void 0 : rows.rowCount
});
}
}, [loading, rows == null ? void 0 : rows.rowCount]);
const renderPageNumbers = () => {
const pageNumbers = [];
const totalP = loading ? lastValues.totalPages : totalPages;
const currentP = loading ? lastValues.currentPage : currentPage;
if (totalP <= 7) {
for (let i = 1; i <= totalP; i += 1) {
pageNumbers.push(i);
}
} else {
pageNumbers.push(1);
if (currentP <= 4) {
for (let i = 2; i <= 5; i += 1) {
pageNumbers.push(i);
}
pageNumbers.push("...");
pageNumbers.push(totalP);
} else if (currentP >= totalP - 3) {
pageNumbers.push("...");
for (let i = totalP - 4; i <= totalP; i += 1) {
pageNumbers.push(i);
}
} else {
pageNumbers.push("...");
for (let i = currentP - 1; i <= currentP + 1; i += 1) {
pageNumbers.push(i);
}
pageNumbers.push("...");
pageNumbers.push(totalP);
}
}
return pageNumbers;
};
const generatePageSizes = (maxSize) => {
const sizes = [];
let current = 10;
while (current <= maxSize) {
if (current !== maxSize) {
sizes.push(current);
}
if (current < 100) {
current += 10;
} else if (current < 1e3) {
current += 100;
} else {
current += 1e3;
}
}
return sizes;
};
const pageSizeOptions = generatePageSizes((_b = rows.rowCount) != null ? _b : 0).map((size) => ({
value: size.toString(),
label: size.toString()
}));
if (!manualPagination || ((_c = rows.rowCount) != null ? _c : 0) <= 1e3) {
pageSizeOptions.push({
value: (_e = (_d = rows.rowCount) == null ? void 0 : _d.toString()) != null ? _e : "0",
label: `Hepsini G\xF6ster (${rows.rowCount})`
});
}
useEffect(() => {
if (manualPagination && !loading && pagination && (pagination == null ? void 0 : pagination.pageIndex) > totalPages - 1) {
setPagination(__spreadProps(__spreadValues({}, pagination), { pageIndex: 0 }));
}
}, [manualPagination, rows.pageCount, setPagination, totalPages, loading]);
const getPageNumber = () => {
var _a2;
if (manualPagination) {
if (totalPages === 1) {
return pageSizeOptions[pageSizeOptions.length - 1].value.toString();
}
const pageSizeOption = pageSizeOptions.find(
(option) => option.value === pagination.pageSize.toString()
);
if (!pageSizeOption) {
return pageSizeOptions[0].value.toString();
}
if (pagination.pageSize >= ((_a2 = rows == null ? void 0 : rows.rowCount) != null ? _a2 : 0)) {
return pagination.pageSize.toString();
}
return pagination.pageSize.toString();
}
if (pageSize >= rows.data.length) {
return rows.data.length.toString();
}
return pageSize.toString();
};
return /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-2 select-none mt-auto sticky z-20 bottom-2 shadow border-t bg-gray-200 p-3 rounded-2xl", children: [
/* @__PURE__ */ jsx6(
Button,
{
size: "icon",
className: "text-gray-800",
variant: "ghost",
onClick: () => table ? table.previousPage() : setPagination((currentValue) => __spreadProps(__spreadValues({}, currentValue), {
pageIndex: currentValue.pageIndex - 1
})),
disabled: table ? !table.getCanPreviousPage() : pagination.pageIndex === 0,
children: /* @__PURE__ */ jsx6(ChevronLeft, {})
}
),
/* @__PURE__ */ jsx6("div", { className: "flex items-center gap-1", children: renderPageNumbers().map((pageNum, idx) => /* @__PURE__ */ jsx6(React.Fragment, { children: pageNum === "..." ? /* @__PURE__ */ jsx6("span", { className: "px-2 h-8 w-8 flex items-center justify-center text-gray-800", children: "..." }) : /* @__PURE__ */ jsx6("div", { children: /* @__PURE__ */ jsx6(
Button,
{
variant: currentPage === pageNum ? "default" : "ghost",
className: "min-w-[32px] h-8 flex items-center justify-center px-1",
onClick: () => {
const newPage = pageNum - 1;
if (table) {
table.setPageIndex(newPage);
} else {
setPagination((prev) => __spreadProps(__spreadValues({}, prev), {
pageIndex: newPage
}));
}
},
children: pageNum
}
) }) }, idx)) }),
/* @__PURE__ */ jsx6(
Button,
{
size: "icon",
className: "text-gray-800",
variant: "ghost",
onClick: () => table ? table.nextPage() : setPagination((currentValue) => __spreadProps(__spreadValues({}, currentValue), {
pageIndex: currentValue.pageIndex + 1
})),
disabled: table ? !table.getCanNextPage() : pagination.pageIndex === totalPages - 1,
children: /* @__PURE__ */ jsx6(ChevronRight, {})
}
),
!hidePageSize && /* @__PURE__ */ jsx6(
FormSelect,
{
onChange: (e) => {
if (table) {
table.setPageSize(Number(e.target.value));
} else {
setPagination(__spreadProps(__spreadValues({}, pagination), {
pageSize: Number(e.target.value)
}));
}
},
value: getPageNumber(),
options: pageSizeOptions
}
),
showTotalCount && /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-4 text-sm text-gray-700 bg-white p-2 rounded-md shadow-md", children: [
/* @__PURE__ */ jsx6("span", { className: "font-semibold", children: `${currentPage} / ${loading ? lastValues.totalPages : totalPages}` }),
/* @__PURE__ */ jsxs4("span", { className: "text-gray-500 flex items-center", children: [
/* @__PURE__ */ jsx6(List, { className: "mr-1" }),
`${table ? table.getFilteredRowModel().rows.length : rows.rowCount === 0 && loading ? lastValues.rowCount : rows.rowCount}`
] })
] })
] });
};
// src/components/CustomTable/Filter.tsx
import { useState as useState2 } from "react";
import { formatISO, isValid, parseISO } from "date-fns";
// src/components/ui/popover.tsx
import * as PopoverPrimitive from "@radix-ui/react-popover";
import { jsx as jsx7 } from "react/jsx-runtime";
function Popover(_a) {
var props = __objRest(_a, []);
return /* @__PURE__ */ jsx7(PopoverPrimitive.Root, __spreadValues({ "data-slot": "popover" }, props));
}
function PopoverTrigger(_a) {
var props = __objRest(_a, []);
return /* @__PURE__ */ jsx7(PopoverPrimitive.Trigger, __spreadValues({ "data-slot": "popover-trigger" }, props));
}
function PopoverContent(_a) {
var _b = _a, {
className,
align = "center",
sideOffset = 4
} = _b, props = __objRest(_b, [
"className",
"align",
"sideOffset"
]);
return /* @__PURE__ */ jsx7(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsx7(
PopoverPrimitive.Content,
__spreadValues({
"data-slot": "popover-content",
align,
sideOffset,
className: cn(
"z-[99999] w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className
)
}, props)
) });
}
// src/components/FormComponents/FormInput/FormInput.tsx
import { cva as cva2 } from "class-variance-authority";
// src/components/ui/input.tsx
import { NumericFormat } from "react-number-format";
import { jsx as jsx8 } from "react/jsx-runtime";
var Input = (_a) => {
var _b = _a, {
className,
type,
numeric,
decimalScale = 2,
allowNegative = true
} = _b, props = __objRest(_b, [
"className",
"type",
"numeric",
"decimalScale",
"allowNegative"
]);
var _b2;
if (numeric) {
const _a2 = props, { value } = _a2, numericProps = __objRest(_a2, ["value"]);
return /* @__PURE__ */ jsx8(
NumericFormat,
__spreadProps(__spreadValues({
decimalScale,
value: (_b2 = value == null ? void 0 : value.toString()) != null ? _b2 : ""
}, numericProps), {
className: cn(
"flex h-10 w-full rounded-md border border-input bg-transparent placeholder:text-zinc-600 px-3 py-1 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
className
),
allowNegative,
allowedDecimalSeparators: [","]
})
);
}
return /* @__PURE__ */ jsx8(
"input",
__spreadValues({
type,
className: cn(
"flex h-10 w-full rounded-md border border-input bg-transparent placeholder:text-zinc-600 px-3 py-1 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
className
)
}, props)
);
};
Input.displayName = "Input";
// src/components/FormComponents/FormInput/FormInput.tsx
import { jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
var inputVariants = cva2("", {
variants: {
variant: {
default: "block w-full rounded-lg h-10 py-2 text-sm border-zinc-200 border focus:border-zinc-400 placeholder:text-zinc-600"
}
},
defaultVariants: {
variant: "default"
}
});
var FormInput = (_a) => {
var _b = _a, {
label,
variant,
className,
type,
numeric,
showMessage = true,
decimalScale = 2,
allowNegative = true
} = _b, props = __objRest(_b, [
"label",
"variant",
"className",
"type",
"numeric",
"showMessage",
"decimalScale",
"allowNegative"
]);
return /* @__PURE__ */ jsxs5("div", { children: [
label && /* @__PURE__ */ jsx9("div", { className: "text-sm font-medium text-zinc-800 mb-1 block", children: label }),
/* @__PURE__ */ jsx9("div", { className: "relative flex items-center", children: /* @__PURE__ */ jsx9(
Input,
__spreadProps(__spreadValues({
className: cn(
inputVariants({
variant
}),
className
),
numeric,
id: props.id,
type,
placeholder: props.placeholder
}, props), {
decimalScale,
allowNegative
})
) })
] });
};
FormInput.displayName = "FormInput";
// src/components/CustomTable/Filter.tsx
import { Filter as FilterIcon } from "lucide-react";
// src/components/FormComponents/FormCalendar/FormCalendar.tsx
import { cva as cva3 } from "class-variance-authority";
import { tr } from "date-fns/locale";
import { CalendarIcon } from "lucide-react";
import { format } from "date-fns";
// src/components/ui/calendar.tsx
import { ChevronLeft as ChevronLeft2, ChevronRight as ChevronRight2 } from "lucide-react";
import { DayPicker } from "react-day-picker";
import { jsx as jsx10 } from "react/jsx-runtime";
function Calendar(_a) {
var _b = _a, {
className,
classNames,
showOutsideDays = true
} = _b, props = __objRest(_b, [
"className",
"classNames",
"showOutsideDays"
]);
return /* @__PURE__ */ jsx10(
DayPicker,
__spreadValues({
showOutsideDays,
className: cn("p-3", className),
classNames: __spreadValues({
months: "flex flex-col sm:flex-row gap-2",
month: "flex flex-col gap-4",
caption: "flex justify-center pt-1 relative items-center w-full",
caption_label: "text-sm font-medium",
nav: "flex items-center gap-1",
nav_button: cn(
buttonVariants({ variant: "outline" }),
"size-7 bg-transparent p-0 opacity-50 hover:opacity-100"
),
nav_button_previous: "absolute left-1",
nav_button_next: "absolute right-1",
table: "w-full border-collapse space-x-1",
head_row: "flex",
head_cell: "text-muted-foreground rounded-md w-8 font-normal text-[0.8rem]",
row: "flex w-full mt-2",
cell: cn(
"relative p-0 text-center text-sm focus-within:relative focus-within:z-20 [&:has([aria-selected])]:bg-accent [&:has([aria-selected].day-range-end)]:rounded-r-md",
props.mode === "range" ? "[&:has(>.day-range-end)]:rounded-r-md [&:has(>.day-range-start)]:rounded-l-md first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md" : "[&:has([aria-selected])]:rounded-md"
),
day: cn(
buttonVariants({ variant: "ghost" }),
"size-8 p-0 font-normal aria-selected:opacity-100"
),
day_range_start: "day-range-start aria-selected:bg-primary aria-selected:text-primary-foreground",
day_range_end: "day-range-end aria-selected:bg-primary aria-selected:text-primary-foreground",
day_selected: "bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground",
day_today: "bg-accent text-accent-foreground",
day_outside: "day-outside text-muted-foreground aria-selected:text-muted-foreground",
day_disabled: "text-muted-foreground opacity-50",
day_range_middle: "aria-selected:bg-accent aria-selected:text-accent-foreground",
day_hidden: "invisible"
}, classNames),
components: {
IconLeft: (_a2) => {
var _b2 = _a2, { className: className2 } = _b2, props2 = __objRest(_b2, ["className"]);
return /* @__PURE__ */ jsx10(ChevronLeft2, __spreadValues({ className: cn("size-4", className2) }, props2));
},
IconRight: (_c) => {
var _d = _c, { className: className2 } = _d, props2 = __objRest(_d, ["className"]);
return /* @__PURE__ */ jsx10(ChevronRight2, __spreadValues({ className: cn("size-4", className2) }, props2));
}
}
}, props)
);
}
// src/components/FormComponents/FormCalendar/FormCalendar.tsx
import { useState } from "react";
import { jsx as jsx11, jsxs as jsxs6 } from "react/jsx-runtime";
var calendarVariants = cva3("", {
variants: {
intent: {
primary: [
"bg-opacityGray",
"text-zinc-800",
"border-zinc-600 border rounded-[10px]",
"focus:outline-none focus:ring-2 focus:ring-zinc-800 focus:border-transparent",
"h-[40px]"
],
secondary: ["bg-gray-200", "text-gray-800", "border-gray-400"],
success: ["bg-green-500", "text-white", "border-transparent"],
white: [
"bg-white",
"text-zinc-800",
"border-none",
"focus:outline-none focus:ring-2 focus:ring-zinc-800 focus:border-transparent"
],
transparent: [
"bg-transparent",
"border-none",
"hover:bg-gray-200",
"text-zinc-800",
"disabled:text-text-exp"
],
refresh: [
"bg-green-500/15",
"text-green-500",
"border-none",
"hover:bg-green-500/25"
]
},
hasLeftIcon: {
true: "pl-10",
false: "pl-3"
},
hasRightIcon: {
true: "pr-10 !text-left",
false: "pr-3"
},
hasError: {
true: "border-red-500 border",
false: "border-zinc-600 border"
},
variant: {
default: "block w-full rounded-lg h-10 py-2 text-sm outline-2 placeholder:text-zinc-600",
waitlist: "block w-full rounded-lg h-14 py-2 text-sm outline-2 placeholder:text-zinc-600 bg-white",
filter: 'h-8 placeholder:text-xs text-center w-full rounded-md focus:border-zinc-800 outline-none [&:not(:placeholder-shown)]:border-zinc-800 placeholder:text-zinc-600 [&[type="date"]]:border-input'
}
},
defaultVariants: {
hasLeftIcon: false,
hasRightIcon: false,
hasError: false,
variant: "default"
}
});
var FormCalendar = (_a) => {
var _b = _a, {
label,
className,
value,
disabled
} = _b, props = __objRest(_b, [
"label",
"className",
"value",
"disabled"
]);
const [openCalendar, setOpenCalendar] = useState(false);
return /* @__PURE__ */ jsxs6(Popover, { open: openCalendar, onOpenChange: setOpenCalendar, children: [
/* @__PURE__ */ jsx11(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs6(
"button",
{
type: "button",
className: cn(
"h-10 w-60 flex items-center justify-between bg-transparent border px-3 rounded-lg border-zinc-600/15 text-zinc-800 hover:bg-zinc-600/15",
{ "text-zinc-800": value },
className
),
children: [
value ? format(value, "dd.MM.yyyy") : /* @__PURE__ */ jsx11("span", { children: "Tarih se\xE7" }),
/* @__PURE__ */ jsx11(CalendarIcon, { className: "h-4 w-4" })
]
}
) }),
/* @__PURE__ */ jsx11(PopoverContent, { className: "w-auto p-0", children: /* @__PURE__ */ jsx11(
Calendar,
{
locale: tr,
mode: "single",
disabled,
selected: value,
onSelect: (e) => {
var _a2;
if (typeof e === "undefined") {
return;
}
(_a2 = props.onSelect) == null ? void 0 : _a2.call(props, e);
setOpenCalendar(false);
},
initialFocus: true
}
) })
] });
};
FormCalendar.displayName = "FormCalendar";
// src/components/CustomTable/Filter.tsx
import { motion, AnimatePresence } from "motion/react";
import { Fragment, jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
var parseDateString = (dateString) => {
if (!dateString) return void 0;
try {
if (typeof dateString === "string") {
const parsedDate = parseISO(dateString);
return isValid(parsedDate) ? parsedDate : void 0;
}
return void 0;
} catch (error) {
return void 0;
}
};
var Filter = ({
column,
table
}) => {
var _a;
const [open, setOpen] = useState2(false);
const uniqueValues = Array.from(
new Set(
table.getPreFilteredRowModel().flatRows.map((row) => row.getValue(column.id))
)
);
const columnFilterValue = column.getFilterValue();
const [filteredValue, setFilteredValue] = useState2(columnFilterValue);
const filterType = (_a = column.columnDef.meta) == null ? void 0 : _a.filterType;
const renderFilterInput = () => {
var _a2, _b, _c, _d;
if (filterType === "date") {
return /* @__PURE__ */ jsx12(
motion.div,
{
initial: { opacity: 0, y: -10 },
animate: { opacity: 1, y: 0 },
exit: { opacity: 0, y: -10 },
children: /* @__PURE__ */ jsx12(
FormCalendar,
{
className: "w-full",
value: filteredValue !== void 0 ? parseISO(filteredValue) : columnFilterValue !== void 0 ? parseISO(columnFilterValue) : void 0,
onSelect: (e) => {
setFilteredValue(formatISO(e).split("T")[0]);
},
disabled: (date) => {
const availableDates = table.getPreFilteredRowModel().flatRows.map((row) => {
return parseDateString(row.getValue(column.id));
}).filter((d) => d !== void 0).map((d) => formatISO(d).split("T")[0]);
return !availableDates.includes(formatISO(date).split("T")[0]);
}
}
)
},
"date-filter"
);
}
if (filterType === "number") {
return /* @__PURE__ */ jsxs7(
motion.div,
{
initial: { opacity: 0, y: -10 },
animate: { opacity: 1, y: 0 },
exit: { opacity: 0, y: -10 },
className: "flex gap-3",
children: [
/* @__PURE__ */ jsx12(
FormInput,
{
type: "number",
value: (_a2 = columnFilterValue == null ? void 0 : columnFilterValue[0]) != null ? _a2 : "",
onChange: (e) => setFilteredValue((old) => {
var _a3;
return [
e.target.value,
(_a3 = old == null ? void 0 : old[1]) != null ? _a3 : columnFilterValue == null ? void 0 : columnFilterValue[1]
];
}),
placeholder: "Min",
className: "w-full rounded-lg border border-gray-200 dark:border-gray-800",
numeric: true
}
),
/* @__PURE__ */ jsx12(
FormInput,
{
type: "number",
value: (_b = columnFilterValue == null ? void 0 : columnFilterValue[1]) != null ? _b : "",
onChange: (e) => setFilteredValue((old) => {
var _a3;
return [
(_a3 = old == null ? void 0 : old[0]) != null ? _a3 : columnFilterValue == null ? void 0 : columnFilterValue[0],
e.target.value
];
}),
placeholder: "Maks",
className: "w-full rounded-lg border border-gray-200 dark:border-gray-800",
numeric: true
}
)
]
},
"number-filter"
);
}
if (filterType === "select") {
return /* @__PURE__ */ jsx12(
FormSelect,
{
options: uniqueValues.map((value) => ({
label: value,
value
})),
onChange: (evt) => setFilteredValue(evt.target.value),
onClick: (evt) => evt.stopPropagation(),
placeholder: "Se\xE7iniz",
value: filteredValue !== void 0 ? filteredValue : columnFilterValue != null ? columnFilterValue : ""
}
);
}
if (filterType === "boolean") {
return /* @__PURE__ */ jsx12(
motion.div,
{
initial: { opacity: 0, y: -10 },
animate: { opacity: 1, y: 0 },
exit: { opacity: 0, y: -10 },
children: /* @__PURE__ */ jsx12(
FormSelect,
{
options: [
{ label: "Evet", value: "true" },
{ label: "Hay\u0131r", value: "false" }
],
placeholder: "Se\xE7iniz",
onChange: (evt) => {
setFilteredValue(evt.target.value);
},
value: filteredValue !== void 0 ? filteredValue : (_c = columnFilterValue == null ? void 0 : columnFilterValue.toString()) != null ? _c : "",
className: "rounded-lg border border-gray-200 dark:border-gray-800"
}
)
},
"boolean-filter"
);
}
return /* @__PURE__ */ jsx12(
motion.div,
{
initial: { opacity: 0, y: -10 },
animate: { opacity: 1, y: 0 },
exit: { opacity: 0, y: -10 },
children: /* @__PURE__ */ jsx12(
FormInput,
{
className: "w-full rounded-lg border border-gray-200 dark:border-gray-800",
onChange: (evt) => setFilteredValue(evt.target.value),
onClick: (evt) => evt.stopPropagation(),
placeholder: "Ara",
type: "text",
value: (_d = filteredValue != null ? filteredValue : columnFilterValue) != null ? _d : ""
}
)
},
"string-filter"
);
};
return /* @__PURE__ */ jsxs7(Popover, { open, onOpenChange: setOpen, children: [
/* @__PURE__ */ jsx12(
PopoverTrigger,
{
onClick: (e) => e.stopPropagation(),
className: cn(
"p-1.5 rounded-full transition-colors hover:bg-green-100 group/filter",
{
"bg-green-100": columnFilterValue !== void 0
}
),
children: /* @__PURE__ */ jsx12(motion.div, { whileHover: { scale: 1.1 }, whileTap: { scale: 0.95 }, children: /* @__PURE__ */ jsx12(
FilterIcon,
{
className: cn("size-4 group-hover/filter:text-green-600", {
"text-green-600": columnFilterValue !== void 0,
"text-gray-800": columnFilterValue === void 0
})
}
) })
}
),
/* @__PURE__ */ jsx12(
PopoverContent,
{
onClick: (e) => e.stopPropagation(),
className: "flex flex-col gap-3 p-4 shadow-lg border border-gray-200 dark:border-gray-800 rounded-lg bg-white dark:bg-gray-900",
children: /* @__PURE__ */ jsx12(AnimatePresence, { children: /* @__PURE__ */ jsxs7(Fragment, { children: [
renderFilterInput(),
/* @__PURE__ */ jsxs7("div", { className: "flex gap-2 mt-2", children: [
/* @__PURE__ */ jsx12(
Button,
{
variant: "outline",
className: "flex-1 flex justify-center items-center hover:bg-gray-100 dark:hover:bg-gray-800",
disabled: columnFilterValue === void 0 && filteredValue === void 0,
onClick: () => {
column.setFilterValue("");
setFilteredValue(void 0);
setOpen(false);
},
children: "Temizle"
}
),
/* @__PURE__ */ jsx12(
Button,
{
className: "flex-1 flex justify-center items-center bg-green-600 hover:bg-green-700 text-white",
disabled: !filteredValue,
onClick: () => {
if (filteredValue === "true" || filteredValue === "false") {
column.setFilterValue(filteredValue === "true");
} else {
column.setFilterValue(filteredValue);
}
setFilteredValue(void 0);
setOpen(false);
},
children: "Uygula"
}
)
] })
] }) })
}
)
] });
};
// src/components/CustomTable/index.tsx
import { Fragment as Fragment2, jsx as jsx13, jsxs as jsxs8 } from "react/jsx-runtime";
var CustomTable = ({
tableId,
columns,
rows,
defaultPageSize = 10,
manualPagination = false,
customPagination = false,
defaultPinnedColumns,
cardComponent,
bulkActions,
manualSearch,
rightTop,
leftTop,
viewMode = "table",
pageOffset = 15.5,
scrollable = true,
isLoading = false,
defaultSorting,
maxHeight,
minHeight,
emptyContent
}) => {
var _a, _b, _c, _d;
const { setTableData, tableData } = tableStore_default();
const initialPagination = useMemo(() => {
var _a2;
return ((_a2 = tableData.find((t) => t.tableId === tableId)) == null ? void 0 : _a2.pagination) || {
pageIndex: 0,
pageSize: defaultPageSize
};
}, [tableId, tableData, defaultPageSize]);
const [pagination, setPagination] = useState3(initialPagination);
const initialRowsData = useMemo(
() => {
var _a2, _b2;
return __spreadProps(__spreadValues({}, rows), {
data: rows.data || [],
rowCount: rows.rowCount || ((_a2 = rows.data) == null ? void 0 : _a2.length) || 0,
pageCount: rows.pageCount || Math.ceil(
(rows.rowCount || ((_b2 = rows.data) == null ? void 0 : _b2.length) || 0) / initialPagination.pageSize
)
});
},
[rows, initialPagination.pageSize]
);
const [rowsData, setRowsData] = useState3(initialRowsData);
const [columnPinning, setColumnPinning] = useState3(
defaultPinnedColumns ? {
left: ["select", ...(defaultPinnedColumns == null ? void 0 : defaultPinnedColumns.left) || []],
right: [...(defaultPinnedColumns == null ? void 0 : defaultPinnedColumns.right) || []]
} : {
left: [],
right: []
}
);
const [sorting, setSorting] = useState3(
((_a = tableData.find((t) => t.tableId === tableId)) == null ? void 0 : _a.sorting) || defaultSorting || []
);
const [columnFilters, setColumnFilters] = useState3(
((_b = tableData.find((t) => t.tableId === tableId)) == null ? void 0 : _b.columnFilters) || []
);
const [globalFilter, setGlobalFilter] = useState3(
((_c = tableData.find((t) => t.tableId === tableId)) == null ? void 0 : _c.globalFilter) || ""
);
const [rowSelection, setRowSelection] = useState3(
((_d = tableData.find((t) => t.tableId === tableId)) == null ? void 0 : _d.rowSelection) || {}
);
const weakIncludesStringFn = (srows, columnId, filterValue) => {
const rowValue = srows.getValue(columnId);
if (rowValue == null) return false;
const rowValueString = String(rowValue).toLowerCase();
const filterValueString = String(filterValue).toLowerCase();
return rowValueString.includes(filterValueString) || rowValue === filterValue;
};
useEffect2(() => {
if (!rows.data) return;
if (manualPagination) {
setRowsData((prev) => {
if (prev.data === rows.data && prev.rowCount === rows.rowCount && prev.pageCount === rows.pageCount) {
return prev;
}
return rows;
});
} else {
const newRowCount = rows.rowCount || rows.data.length;
const newPageCount = rows.pageCount || Math.ceil(newRowCount / pagination.pageSize);
setRowsData((prev) => {
if (prev.data === rows.data && prev.rowCount === newRowCount && prev.pageCount === newPageCount) {
return prev;
}
return __spreadProps(__spreadValues({}, rows), {
data: rows.data,
rowCount: newRowCount,
pageCount: newPageCount
});
});
}
}, [rows, pagination.pageSize, manualPagination]);
useEffect2(() => {
setTableData({
tableId,
columnFilters,
columnPinning,
sorting,
pagination,
globalFilter,
rowSelection
});
}, [
tableId,
columnFilters,
columnPinning,
sorting,
pagination,
globalFilter,
rowSelection,
setTableData
]);
const table = useReactTable({
columns,
data: rowsData.data,
getCoreRowModel: getCoreRowModel(),
getSortedRowModel: getSortedRowModel(),
getFilteredRowModel: getFilteredRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getFacetedRowModel: getFacetedRowModel(),
getFacetedUniqueValues: getFacetedUniqueValues(),
getFacetedMinMaxValues: getFacetedMinMaxValues(),
state: {
columnFilters,
columnPinning,
sorting,
pagination,
globalFilter,
rowSelection
},
rowCount: rowsData.rowCount,
onColumnPinningChange: setColumnPinning,
onSortingChange: setSorting,
onPaginationChange: setPagination,
onColumnFiltersChange: setColumnFilters,
onGlobalFilterChange: setGlobalFilter,
onRowSelectionChange: setRowSelection,
globalFilterFn: weakIncludesStringFn,
manualPagination,
enableColumnResizing: true,
columnResizeMode: "onChange",
defaultColumn: {
minSize: 100,
size: 100,
enableResizing: true
},
pageCount: rowsData.pageCount,
manualFiltering: false
});
const tableContainerRef = useRef(null);
const rowVirtualizer = useVirtualizer({
count: Math.max(
pagination.pageSize < table.getFilteredRowModel().rows.length ? pagination.pageSize : table.getFilteredRowModel().rows.length,
0
),
estimateSize: () => 52,
getScrollElement: () => tableContainerRef.current,
measureElement: typeof window !== "undefined" && navigator.userAgent.indexOf("Firefox") === -1 ? (element) => element == null ? void 0 : element.getBoundingClientRect().height : void 0,
overscan: 5
});
const selectedRows = rowsData.data.filter((_, index) => rowSelection[index]);
const actions = {
selectedRows,
pagination,
setRowSelection,
setGlobalFilter,
setPagination,
table
};
const renderBulkActions = () => {
if (typeof bulkActions === "function") {
return bulkActions(actions);
}
return bulkActions;
};
const renderCardComponent = (row) => {
if (typeof cardComponent === "function") {
return cardComponent({ row });
}
return cardComponent;
};
const renderRightTop = () => {
if (typeof rightTop === "function") {
return rightTop(actions);
}
return rightTop;
};
const renderLeftTop = () => {
if (typeof leftTop === "function") {
return leftTop(actions);
}
return leftTop;
};
const renderCustomPagination = () => {
if (typeof customPagination === "function") {
return customPagination(actions);
}
return customPagination;
};
const { rows: rowsModel } = table.getPaginationRowModel();
const virtualItems = rowVirtualizer.getVirtualItems();
const virtualRows = useMemo(() => {
return virtualItems.map((virtualRow) => {
const row = rowsModel[virtualRow.index];
if (!row) return null;
return {
virtualRow,
row,
cells: row.getVisibleCells().map((cell) => {
const header = table.getHeaderGroups().flatMap((headerGroup) => headerGroup.headers).find((h) => h.id === cell.column.id);
return { cell, header };
})
};
});
}, [virtualItems, rowsModel, table]);
useEffect2(() => {
if (!manualPagination) {
const filteredRowCount = table.getState().columnFilters.length === 0 ? rows.data.length : table.getFilteredRowModel().rows.length;
const newPageCount = Math.ceil(filteredRowCount / pagination.pageSize);
setRowsData((prev) => {
return __spreadProps(__spreadValues({}, prev), {
rowCount: filteredRowCount,
pageCount: newPageCount
});
});
if (pagination.pageIndex >= newPageCount) {
setPagination((prev) => __spreadProps(__spreadValues({}, prev), {
pageIndex: Math.max(0, newPageCount - 1)
}));
}
} else {
setRowsData((prev) => {
if (prev.data === rows.data && prev.rowCount === rows.rowCount && prev.pageCount === rows.pageCount) {
return prev;
}
return rows;
});
}
}, [
columnFilters,
globalFilter,
pagination.pageSize,
table,
pagination.pageIndex,
manualPagination,
rows
]);
return /* @__PURE__ */ jsx13("div", { className: "w-full", children: /* @__PURE__ */ jsxs8("div", { className: "rounded-2.5xl px-3 max-w-full grid relative h-full", children: [
bulkActions && /* @__PURE__ */ jsx13(BulkActions_default, { children: renderBulkActions() }),
/* @__PURE__ */ jsxs8("div", { className: "flex flex-col gap-3 transition-none overflow-auto relative", children: [
isLoading && /* @__PURE__ */ jsx13(Loading, {}),
/* @__PURE__ */ jsxs8(
"div",
{
className: `flex justify-between items-center ${!bulkActions && !manualSearch && !manualPagination ? "p-3" : ""}`,
children: [
/* @__PURE__ */ jsxs8("div", { className: "flex items-center h-full flex-1", children: [
!manualSearch && /* @__PURE__ */ jsx13(
"input",
{
className: "h-10 w-full max-w-72 rounded-lg px-3 border border-gray-300",
value: globalFilter,
onChange: (e