@juv/codego-react-ui 3.4.8 → 3.5.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/index.cjs +276 -30
- package/dist/index.d.cts +33 -2
- package/dist/index.d.ts +33 -2
- package/dist/index.global.js +276 -30
- package/dist/index.js +276 -30
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6359,7 +6359,7 @@ import { createPortal as createPortal3 } from "react-dom";
|
|
|
6359
6359
|
import axios3 from "axios";
|
|
6360
6360
|
import { ChevronLeft as ChevronLeft6, ChevronRight as ChevronRight8, Search as Search5, Trash2 as Trash22, ChevronsUpDown, ChevronUp, ChevronDown as ChevronDown4, X as X9, Eye as Eye2, Pencil as Pencil2, Trash as Trash3, Loader2 as Loader22 } from "lucide-react";
|
|
6361
6361
|
import { Fragment as Fragment12, jsx as jsx32, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
6362
|
-
function useServerTable({ url, params, encrypt, key, decryptPayloadLog, columnOverrides, debounce = 300, transform, manual = false, refresh: refreshEnabled = false, refreshInterval = 0, hardReload, onSuccess, onError }) {
|
|
6362
|
+
function useServerTable({ url, params, encrypt, key, decryptPayloadLog, columnOverrides, debounce = 300, transform, manual = false, refresh: refreshEnabled = false, refreshInterval = 0, hardReload, onSuccess, onError, filter: filterFields, sort: sortKeys }) {
|
|
6363
6363
|
const [data, setData] = React28.useState([]);
|
|
6364
6364
|
const [columns, setColumns] = React28.useState([]);
|
|
6365
6365
|
const [currentPage, setCurrentPage] = React28.useState(1);
|
|
@@ -6369,6 +6369,15 @@ function useServerTable({ url, params, encrypt, key, decryptPayloadLog, columnOv
|
|
|
6369
6369
|
const [tick, setTick] = React28.useState(0);
|
|
6370
6370
|
const [searchValue, setSearchValue] = React28.useState("");
|
|
6371
6371
|
const debounceTimer = React28.useRef(void 0);
|
|
6372
|
+
const [filterValues, setFilterValues] = React28.useState(() => {
|
|
6373
|
+
const init = {};
|
|
6374
|
+
filterFields?.forEach((f) => {
|
|
6375
|
+
init[f.key] = f.type === "checkbox" || f.type === "toggle" ? false : "";
|
|
6376
|
+
});
|
|
6377
|
+
return init;
|
|
6378
|
+
});
|
|
6379
|
+
const [sortKey, setSortKey] = React28.useState("");
|
|
6380
|
+
const [sortDir, setSortDir] = React28.useState("asc");
|
|
6372
6381
|
React28.useEffect(() => {
|
|
6373
6382
|
if (hardReload) hardReload.current = () => setTick((t) => t + 1);
|
|
6374
6383
|
}, [hardReload]);
|
|
@@ -6377,13 +6386,32 @@ function useServerTable({ url, params, encrypt, key, decryptPayloadLog, columnOv
|
|
|
6377
6386
|
const id = setInterval(() => setTick((t) => t + 1), refreshInterval);
|
|
6378
6387
|
return () => clearInterval(id);
|
|
6379
6388
|
}, [refreshInterval]);
|
|
6389
|
+
const activeFilterParams = React28.useMemo(() => {
|
|
6390
|
+
const out = {};
|
|
6391
|
+
filterFields?.forEach((f) => {
|
|
6392
|
+
const v = filterValues[f.key];
|
|
6393
|
+
if (f.type === "checkbox" || f.type === "toggle") {
|
|
6394
|
+
if (v) out[f.key] = 1;
|
|
6395
|
+
} else if (f.type === "date-range") {
|
|
6396
|
+
if (v?.from) out[`${f.key}_from`] = v.from;
|
|
6397
|
+
if (v?.to) out[`${f.key}_to`] = v.to;
|
|
6398
|
+
} else if (v !== "" && v !== null && v !== void 0) {
|
|
6399
|
+
out[f.key] = v;
|
|
6400
|
+
}
|
|
6401
|
+
});
|
|
6402
|
+
if (sortKey) {
|
|
6403
|
+
out.sort = sortKey;
|
|
6404
|
+
out.direction = sortDir;
|
|
6405
|
+
}
|
|
6406
|
+
return out;
|
|
6407
|
+
}, [filterValues, sortKey, sortDir, filterFields]);
|
|
6380
6408
|
React28.useEffect(() => {
|
|
6381
6409
|
if (manual && tick === 0) return;
|
|
6382
6410
|
let cancelled = false;
|
|
6383
6411
|
setLoading(true);
|
|
6384
6412
|
setError(null);
|
|
6385
6413
|
axios3.get(url, {
|
|
6386
|
-
params: { ...params, page: currentPage, search: searchValue }
|
|
6414
|
+
params: { ...params, ...activeFilterParams, page: currentPage, search: searchValue }
|
|
6387
6415
|
}).then(({ data: res }) => {
|
|
6388
6416
|
if (cancelled) return;
|
|
6389
6417
|
const payload = encrypt ? decryptLaravelPayload(res, key) : res;
|
|
@@ -6429,15 +6457,184 @@ function useServerTable({ url, params, encrypt, key, decryptPayloadLog, columnOv
|
|
|
6429
6457
|
return () => {
|
|
6430
6458
|
cancelled = true;
|
|
6431
6459
|
};
|
|
6432
|
-
}, [url, currentPage, tick, JSON.stringify(params), encrypt, decryptPayloadLog, JSON.stringify(columnOverrides), searchValue]);
|
|
6460
|
+
}, [url, currentPage, tick, JSON.stringify(params), JSON.stringify(activeFilterParams), encrypt, decryptPayloadLog, JSON.stringify(columnOverrides), searchValue]);
|
|
6433
6461
|
const handleSearchChange = (value) => {
|
|
6434
6462
|
setSearchValue(value);
|
|
6435
6463
|
setCurrentPage(1);
|
|
6436
6464
|
if (debounceTimer.current) clearTimeout(debounceTimer.current);
|
|
6437
|
-
debounceTimer.current = setTimeout(() =>
|
|
6438
|
-
|
|
6439
|
-
|
|
6465
|
+
debounceTimer.current = setTimeout(() => setTick((t) => t + 1), debounce);
|
|
6466
|
+
};
|
|
6467
|
+
const handleFilterChange = (key2, value) => {
|
|
6468
|
+
setFilterValues((prev) => ({ ...prev, [key2]: value }));
|
|
6469
|
+
setCurrentPage(1);
|
|
6470
|
+
setTick((t) => t + 1);
|
|
6471
|
+
};
|
|
6472
|
+
const handleClearFilters = () => {
|
|
6473
|
+
const reset = {};
|
|
6474
|
+
filterFields?.forEach((f) => {
|
|
6475
|
+
reset[f.key] = f.type === "checkbox" || f.type === "toggle" ? false : "";
|
|
6476
|
+
});
|
|
6477
|
+
setFilterValues(reset);
|
|
6478
|
+
setSortKey("");
|
|
6479
|
+
setSortDir("asc");
|
|
6480
|
+
setCurrentPage(1);
|
|
6481
|
+
setTick((t) => t + 1);
|
|
6440
6482
|
};
|
|
6483
|
+
const hasActiveFilters = filterFields?.some((f) => {
|
|
6484
|
+
const v = filterValues[f.key];
|
|
6485
|
+
return f.type === "checkbox" || f.type === "toggle" ? !!v : v !== "" && v !== null && v !== void 0;
|
|
6486
|
+
}) || !!sortKey;
|
|
6487
|
+
const filterBar = filterFields?.length || sortKeys?.length ? /* @__PURE__ */ jsxs30("div", { className: "flex flex-wrap items-end gap-3 rounded-xl border border-border bg-muted/30 px-4 py-3", children: [
|
|
6488
|
+
filterFields?.map((f) => {
|
|
6489
|
+
const label = f.label ?? f.key.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
6490
|
+
const value = filterValues[f.key];
|
|
6491
|
+
const opts = (f.options ?? []).map(
|
|
6492
|
+
(o) => typeof o === "string" ? { label: o, value: o } : o
|
|
6493
|
+
);
|
|
6494
|
+
if (f.type === "checkbox") return /* @__PURE__ */ jsxs30("label", { className: "flex items-center gap-2 cursor-pointer select-none", children: [
|
|
6495
|
+
/* @__PURE__ */ jsx32(
|
|
6496
|
+
"input",
|
|
6497
|
+
{
|
|
6498
|
+
type: "checkbox",
|
|
6499
|
+
checked: !!value,
|
|
6500
|
+
onChange: (e) => handleFilterChange(f.key, e.target.checked),
|
|
6501
|
+
className: "h-4 w-4 rounded accent-primary"
|
|
6502
|
+
}
|
|
6503
|
+
),
|
|
6504
|
+
/* @__PURE__ */ jsx32("span", { className: "text-xs font-medium text-foreground", children: label })
|
|
6505
|
+
] }, f.key);
|
|
6506
|
+
if (f.type === "toggle") return /* @__PURE__ */ jsxs30("label", { className: "flex items-center gap-2 cursor-pointer select-none", children: [
|
|
6507
|
+
/* @__PURE__ */ jsx32(
|
|
6508
|
+
"button",
|
|
6509
|
+
{
|
|
6510
|
+
type: "button",
|
|
6511
|
+
role: "switch",
|
|
6512
|
+
"aria-checked": !!value,
|
|
6513
|
+
onClick: () => handleFilterChange(f.key, !value),
|
|
6514
|
+
className: cn(
|
|
6515
|
+
"relative inline-flex h-5 w-9 shrink-0 rounded-full border-2 border-transparent transition-colors",
|
|
6516
|
+
value ? "bg-primary" : "bg-muted"
|
|
6517
|
+
),
|
|
6518
|
+
children: /* @__PURE__ */ jsx32("span", { className: cn(
|
|
6519
|
+
"pointer-events-none inline-block h-4 w-4 rounded-full bg-white shadow-sm transition-transform",
|
|
6520
|
+
value ? "translate-x-4" : "translate-x-0"
|
|
6521
|
+
) })
|
|
6522
|
+
}
|
|
6523
|
+
),
|
|
6524
|
+
/* @__PURE__ */ jsx32("span", { className: "text-xs font-medium text-foreground", children: label })
|
|
6525
|
+
] }, f.key);
|
|
6526
|
+
if (f.type === "select") return /* @__PURE__ */ jsxs30("div", { className: "flex flex-col gap-1", children: [
|
|
6527
|
+
/* @__PURE__ */ jsx32("span", { className: "text-[10px] font-semibold uppercase tracking-wider text-muted-foreground", children: label }),
|
|
6528
|
+
/* @__PURE__ */ jsxs30(
|
|
6529
|
+
"select",
|
|
6530
|
+
{
|
|
6531
|
+
value: value ?? "",
|
|
6532
|
+
onChange: (e) => handleFilterChange(f.key, e.target.value),
|
|
6533
|
+
className: "h-8 min-w-[120px] rounded-lg border border-border bg-background px-2 text-xs text-foreground focus:outline-none focus:ring-2 focus:ring-ring transition-colors",
|
|
6534
|
+
children: [
|
|
6535
|
+
/* @__PURE__ */ jsx32("option", { value: "", children: f.placeholder ?? `All ${label}` }),
|
|
6536
|
+
opts.map((o) => /* @__PURE__ */ jsx32("option", { value: o.value, children: o.label }, o.value))
|
|
6537
|
+
]
|
|
6538
|
+
}
|
|
6539
|
+
)
|
|
6540
|
+
] }, f.key);
|
|
6541
|
+
if (f.type === "date" || f.type === "date-time") return /* @__PURE__ */ jsxs30("div", { className: "flex flex-col gap-1", children: [
|
|
6542
|
+
/* @__PURE__ */ jsx32("span", { className: "text-[10px] font-semibold uppercase tracking-wider text-muted-foreground", children: label }),
|
|
6543
|
+
/* @__PURE__ */ jsx32(
|
|
6544
|
+
"input",
|
|
6545
|
+
{
|
|
6546
|
+
type: f.type === "date-time" ? "datetime-local" : "date",
|
|
6547
|
+
value: value ?? "",
|
|
6548
|
+
onChange: (e) => handleFilterChange(f.key, e.target.value),
|
|
6549
|
+
className: "h-8 rounded-lg border border-border bg-background px-2 text-xs text-foreground focus:outline-none focus:ring-2 focus:ring-ring transition-colors"
|
|
6550
|
+
}
|
|
6551
|
+
)
|
|
6552
|
+
] }, f.key);
|
|
6553
|
+
if (f.type === "date-range") return /* @__PURE__ */ jsxs30("div", { className: "flex flex-col gap-1", children: [
|
|
6554
|
+
/* @__PURE__ */ jsx32("span", { className: "text-[10px] font-semibold uppercase tracking-wider text-muted-foreground", children: label }),
|
|
6555
|
+
/* @__PURE__ */ jsxs30("div", { className: "flex items-center gap-1.5", children: [
|
|
6556
|
+
/* @__PURE__ */ jsx32(
|
|
6557
|
+
"input",
|
|
6558
|
+
{
|
|
6559
|
+
type: "date",
|
|
6560
|
+
value: value?.from ?? "",
|
|
6561
|
+
onChange: (e) => handleFilterChange(f.key, { ...value, from: e.target.value }),
|
|
6562
|
+
className: "h-8 rounded-lg border border-border bg-background px-2 text-xs text-foreground focus:outline-none focus:ring-2 focus:ring-ring transition-colors"
|
|
6563
|
+
}
|
|
6564
|
+
),
|
|
6565
|
+
/* @__PURE__ */ jsx32("span", { className: "text-xs text-muted-foreground", children: "\u2013" }),
|
|
6566
|
+
/* @__PURE__ */ jsx32(
|
|
6567
|
+
"input",
|
|
6568
|
+
{
|
|
6569
|
+
type: "date",
|
|
6570
|
+
value: value?.to ?? "",
|
|
6571
|
+
onChange: (e) => handleFilterChange(f.key, { ...value, to: e.target.value }),
|
|
6572
|
+
className: "h-8 rounded-lg border border-border bg-background px-2 text-xs text-foreground focus:outline-none focus:ring-2 focus:ring-ring transition-colors"
|
|
6573
|
+
}
|
|
6574
|
+
)
|
|
6575
|
+
] })
|
|
6576
|
+
] }, f.key);
|
|
6577
|
+
return /* @__PURE__ */ jsxs30("div", { className: "flex flex-col gap-1", children: [
|
|
6578
|
+
/* @__PURE__ */ jsx32("span", { className: "text-[10px] font-semibold uppercase tracking-wider text-muted-foreground", children: label }),
|
|
6579
|
+
/* @__PURE__ */ jsx32(
|
|
6580
|
+
"input",
|
|
6581
|
+
{
|
|
6582
|
+
type: "text",
|
|
6583
|
+
value: value ?? "",
|
|
6584
|
+
placeholder: f.placeholder ?? `Filter ${label}\u2026`,
|
|
6585
|
+
onChange: (e) => handleFilterChange(f.key, e.target.value),
|
|
6586
|
+
className: "h-8 min-w-[140px] rounded-lg border border-border bg-background px-3 text-xs text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring transition-colors"
|
|
6587
|
+
}
|
|
6588
|
+
)
|
|
6589
|
+
] }, f.key);
|
|
6590
|
+
}),
|
|
6591
|
+
sortKeys?.length ? /* @__PURE__ */ jsxs30("div", { className: "flex flex-col gap-1", children: [
|
|
6592
|
+
/* @__PURE__ */ jsx32("span", { className: "text-[10px] font-semibold uppercase tracking-wider text-muted-foreground", children: "Sort by" }),
|
|
6593
|
+
/* @__PURE__ */ jsxs30("div", { className: "flex items-center gap-1.5", children: [
|
|
6594
|
+
/* @__PURE__ */ jsxs30(
|
|
6595
|
+
"select",
|
|
6596
|
+
{
|
|
6597
|
+
value: sortKey,
|
|
6598
|
+
onChange: (e) => {
|
|
6599
|
+
setSortKey(e.target.value);
|
|
6600
|
+
setCurrentPage(1);
|
|
6601
|
+
setTick((t) => t + 1);
|
|
6602
|
+
},
|
|
6603
|
+
className: "h-8 min-w-[120px] rounded-lg border border-border bg-background px-2 text-xs text-foreground focus:outline-none focus:ring-2 focus:ring-ring transition-colors",
|
|
6604
|
+
children: [
|
|
6605
|
+
/* @__PURE__ */ jsx32("option", { value: "", children: "Default" }),
|
|
6606
|
+
sortKeys.map((k) => /* @__PURE__ */ jsx32("option", { value: k, children: k.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()) }, k))
|
|
6607
|
+
]
|
|
6608
|
+
}
|
|
6609
|
+
),
|
|
6610
|
+
sortKey && /* @__PURE__ */ jsx32(
|
|
6611
|
+
"button",
|
|
6612
|
+
{
|
|
6613
|
+
type: "button",
|
|
6614
|
+
onClick: () => {
|
|
6615
|
+
setSortDir((d) => d === "asc" ? "desc" : "asc");
|
|
6616
|
+
setTick((t) => t + 1);
|
|
6617
|
+
},
|
|
6618
|
+
className: "flex h-8 w-8 items-center justify-center rounded-lg border border-border bg-background text-muted-foreground hover:text-foreground hover:bg-muted transition-colors",
|
|
6619
|
+
title: sortDir === "asc" ? "Ascending" : "Descending",
|
|
6620
|
+
children: sortDir === "asc" ? /* @__PURE__ */ jsx32(ChevronUp, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx32(ChevronDown4, { className: "h-3.5 w-3.5" })
|
|
6621
|
+
}
|
|
6622
|
+
)
|
|
6623
|
+
] })
|
|
6624
|
+
] }) : null,
|
|
6625
|
+
hasActiveFilters && /* @__PURE__ */ jsxs30(
|
|
6626
|
+
"button",
|
|
6627
|
+
{
|
|
6628
|
+
type: "button",
|
|
6629
|
+
onClick: handleClearFilters,
|
|
6630
|
+
className: "flex h-8 items-center gap-1.5 self-end rounded-lg border border-border bg-background px-3 text-xs font-medium text-muted-foreground hover:bg-muted hover:text-foreground transition-colors",
|
|
6631
|
+
children: [
|
|
6632
|
+
/* @__PURE__ */ jsx32(X9, { className: "h-3 w-3" }),
|
|
6633
|
+
" Clear"
|
|
6634
|
+
]
|
|
6635
|
+
}
|
|
6636
|
+
)
|
|
6637
|
+
] }) : null;
|
|
6441
6638
|
return {
|
|
6442
6639
|
data,
|
|
6443
6640
|
columns,
|
|
@@ -6446,6 +6643,7 @@ function useServerTable({ url, params, encrypt, key, decryptPayloadLog, columnOv
|
|
|
6446
6643
|
serverPagination: pagination ? { pagination, currentPage, goToPage: (page) => setCurrentPage(page) } : null,
|
|
6447
6644
|
loading,
|
|
6448
6645
|
error,
|
|
6646
|
+
filterBar,
|
|
6449
6647
|
goToPage: (page) => setCurrentPage(page),
|
|
6450
6648
|
reload: () => setTick((t) => t + 1),
|
|
6451
6649
|
refresh: () => setTick((t) => t + 1),
|
|
@@ -7155,6 +7353,9 @@ function Table({
|
|
|
7155
7353
|
renderExpanded,
|
|
7156
7354
|
columnVisibility,
|
|
7157
7355
|
onColumnVisibilityChange,
|
|
7356
|
+
columnVisibilityIcon,
|
|
7357
|
+
filterBar,
|
|
7358
|
+
filterableIcon,
|
|
7158
7359
|
exportable = false,
|
|
7159
7360
|
onExport,
|
|
7160
7361
|
virtualized = false,
|
|
@@ -7175,6 +7376,8 @@ function Table({
|
|
|
7175
7376
|
const [sortKey, setSortKey] = React28.useState(null);
|
|
7176
7377
|
const [sortDir, setSortDir] = React28.useState(null);
|
|
7177
7378
|
const [bulkLoading, setBulkLoading] = React28.useState(false);
|
|
7379
|
+
const [bulkConfirm, setBulkConfirm] = React28.useState(null);
|
|
7380
|
+
const [filterBarOpen, setFilterBarOpen] = React28.useState(false);
|
|
7178
7381
|
const [expandedIds, setExpandedIds] = React28.useState(/* @__PURE__ */ new Set());
|
|
7179
7382
|
const [dragOverId, setDragOverId] = React28.useState(null);
|
|
7180
7383
|
const [focusedRowIdx, setFocusedRowIdx] = React28.useState(-1);
|
|
@@ -7311,7 +7514,7 @@ function Table({
|
|
|
7311
7514
|
const unselectedCount = totalRows - selectedIds.length;
|
|
7312
7515
|
const handleSelectAllRecords = () => setSelectedIds(filteredData.map((item) => String(item[idKey])));
|
|
7313
7516
|
const handleUnselectAll = () => setSelectedIds([]);
|
|
7314
|
-
const
|
|
7517
|
+
const execBulkDeleteSelected = async () => {
|
|
7315
7518
|
if (!bulkDeleteBaseUrl || selectedIds.length === 0) {
|
|
7316
7519
|
onBulkDelete?.(selectedIds);
|
|
7317
7520
|
setSelectedIds([]);
|
|
@@ -7333,7 +7536,7 @@ function Table({
|
|
|
7333
7536
|
setBulkLoading(false);
|
|
7334
7537
|
}
|
|
7335
7538
|
};
|
|
7336
|
-
const
|
|
7539
|
+
const execDeleteAll = async () => {
|
|
7337
7540
|
if (!bulkDeleteBaseUrl) return;
|
|
7338
7541
|
setBulkLoading(true);
|
|
7339
7542
|
try {
|
|
@@ -7400,10 +7603,22 @@ function Table({
|
|
|
7400
7603
|
]
|
|
7401
7604
|
}
|
|
7402
7605
|
),
|
|
7606
|
+
unselectedCount > 0 && /* @__PURE__ */ jsxs30(
|
|
7607
|
+
"button",
|
|
7608
|
+
{
|
|
7609
|
+
onClick: handleSelectAllRecords,
|
|
7610
|
+
disabled: bulkLoading,
|
|
7611
|
+
className: "inline-flex items-center gap-1.5 rounded-lg border border-border bg-muted/50 px-3 py-1.5 text-xs font-medium text-muted-foreground hover:bg-muted transition-colors disabled:opacity-40",
|
|
7612
|
+
children: [
|
|
7613
|
+
"Select all ",
|
|
7614
|
+
unselectedCount
|
|
7615
|
+
]
|
|
7616
|
+
}
|
|
7617
|
+
),
|
|
7403
7618
|
/* @__PURE__ */ jsxs30(
|
|
7404
7619
|
"button",
|
|
7405
7620
|
{
|
|
7406
|
-
onClick:
|
|
7621
|
+
onClick: () => setBulkConfirm("selected"),
|
|
7407
7622
|
disabled: bulkLoading,
|
|
7408
7623
|
className: "inline-flex items-center gap-1.5 rounded-lg bg-danger/10 border border-danger/20 px-3 py-1.5 text-xs font-medium text-danger hover:bg-danger/20 transition-colors disabled:opacity-40",
|
|
7409
7624
|
children: [
|
|
@@ -7413,30 +7628,29 @@ function Table({
|
|
|
7413
7628
|
" selected"
|
|
7414
7629
|
]
|
|
7415
7630
|
}
|
|
7631
|
+
),
|
|
7632
|
+
bulkDeleteBaseUrl && /* @__PURE__ */ jsxs30(
|
|
7633
|
+
"button",
|
|
7634
|
+
{
|
|
7635
|
+
onClick: () => setBulkConfirm("all"),
|
|
7636
|
+
disabled: bulkLoading,
|
|
7637
|
+
className: "inline-flex items-center gap-1.5 rounded-lg bg-danger/10 border border-danger/20 px-3 py-1.5 text-xs font-medium text-danger hover:bg-danger/20 transition-colors disabled:opacity-40",
|
|
7638
|
+
children: [
|
|
7639
|
+
bulkLoading ? /* @__PURE__ */ jsx32(Loader22, { className: "h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ jsx32(Trash22, { className: "h-3.5 w-3.5" }),
|
|
7640
|
+
"Delete all"
|
|
7641
|
+
]
|
|
7642
|
+
}
|
|
7416
7643
|
)
|
|
7417
7644
|
] }),
|
|
7418
|
-
|
|
7419
|
-
"button",
|
|
7420
|
-
{
|
|
7421
|
-
onClick: handleSelectAllRecords,
|
|
7422
|
-
disabled: bulkLoading,
|
|
7423
|
-
className: "inline-flex items-center gap-1.5 rounded-lg border border-border bg-muted/50 px-3 py-1.5 text-xs font-medium text-muted-foreground hover:bg-muted transition-colors disabled:opacity-40",
|
|
7424
|
-
children: [
|
|
7425
|
-
"Select all ",
|
|
7426
|
-
unselectedCount
|
|
7427
|
-
]
|
|
7428
|
-
}
|
|
7429
|
-
),
|
|
7430
|
-
selectable && bulkDeleteBaseUrl && /* @__PURE__ */ jsxs30(
|
|
7645
|
+
filterBar && /* @__PURE__ */ jsx32(
|
|
7431
7646
|
"button",
|
|
7432
7647
|
{
|
|
7433
|
-
onClick:
|
|
7434
|
-
|
|
7435
|
-
|
|
7436
|
-
|
|
7437
|
-
|
|
7438
|
-
|
|
7439
|
-
]
|
|
7648
|
+
onClick: () => setFilterBarOpen((o) => !o),
|
|
7649
|
+
className: cn(
|
|
7650
|
+
"inline-flex items-center gap-1.5 rounded-lg border px-3 py-1.5 text-xs font-medium transition-colors",
|
|
7651
|
+
filterBarOpen ? "border-primary bg-primary/10 text-primary hover:bg-primary/20" : "border-border bg-muted/50 text-muted-foreground hover:bg-muted"
|
|
7652
|
+
),
|
|
7653
|
+
children: filterableIcon ?? "Filter"
|
|
7440
7654
|
}
|
|
7441
7655
|
),
|
|
7442
7656
|
exportable && /* @__PURE__ */ jsxs30("div", { className: "relative group", children: [
|
|
@@ -7452,7 +7666,7 @@ function Table({
|
|
|
7452
7666
|
)) })
|
|
7453
7667
|
] }),
|
|
7454
7668
|
columnVisibility && onColumnVisibilityChange && /* @__PURE__ */ jsxs30("div", { className: "relative group", children: [
|
|
7455
|
-
/* @__PURE__ */ jsx32("button", { className: "inline-flex items-center gap-1.5 rounded-lg border border-border bg-muted/50 px-3 py-1.5 text-xs font-medium text-muted-foreground hover:bg-muted transition-colors", children: "Columns" }),
|
|
7669
|
+
/* @__PURE__ */ jsx32("button", { className: "inline-flex items-center gap-1.5 rounded-lg border border-border bg-muted/50 px-3 py-1.5 text-xs font-medium text-muted-foreground hover:bg-muted transition-colors", children: columnVisibilityIcon ?? "Columns" }),
|
|
7456
7670
|
/* @__PURE__ */ jsx32("div", { className: "absolute right-0 top-full mt-1 z-20 hidden group-hover:flex flex-col min-w-[150px] rounded-xl border border-border bg-card shadow-lg overflow-hidden p-2 gap-1", children: columns.map((col) => /* @__PURE__ */ jsxs30("label", { className: "flex items-center gap-2 px-2 py-1 rounded-lg hover:bg-muted cursor-pointer text-xs", children: [
|
|
7457
7671
|
/* @__PURE__ */ jsx32(
|
|
7458
7672
|
"input",
|
|
@@ -7474,6 +7688,7 @@ function Table({
|
|
|
7474
7688
|
] })
|
|
7475
7689
|
] })
|
|
7476
7690
|
] }),
|
|
7691
|
+
filterBar && filterBarOpen && /* @__PURE__ */ jsx32("div", { children: filterBar }),
|
|
7477
7692
|
loading && /* @__PURE__ */ jsxs30("div", { className: "flex items-center justify-center py-12 text-muted-foreground gap-2", children: [
|
|
7478
7693
|
/* @__PURE__ */ jsx32(Loader22, { className: "h-5 w-5 animate-spin" }),
|
|
7479
7694
|
/* @__PURE__ */ jsx32("span", { className: "text-sm", children: "Loading\u2026" })
|
|
@@ -7867,6 +8082,37 @@ function Table({
|
|
|
7867
8082
|
}
|
|
7868
8083
|
}
|
|
7869
8084
|
}
|
|
8085
|
+
),
|
|
8086
|
+
bulkConfirm && createPortal3(
|
|
8087
|
+
/* @__PURE__ */ jsx32(
|
|
8088
|
+
"div",
|
|
8089
|
+
{
|
|
8090
|
+
className: "fixed inset-0 z-50 flex items-center justify-center p-4",
|
|
8091
|
+
style: { background: "rgba(0,0,0,0.5)" },
|
|
8092
|
+
onMouseDown: (e) => {
|
|
8093
|
+
if (e.target === e.currentTarget) setBulkConfirm(null);
|
|
8094
|
+
},
|
|
8095
|
+
children: /* @__PURE__ */ jsxs30("div", { className: "relative w-full max-w-md rounded-2xl border border-border bg-card shadow-2xl flex flex-col", children: [
|
|
8096
|
+
/* @__PURE__ */ jsxs30("div", { className: "flex items-center justify-between px-6 py-4 border-b border-border", children: [
|
|
8097
|
+
/* @__PURE__ */ jsx32("h2", { className: "text-base font-semibold", children: "Confirm Delete" }),
|
|
8098
|
+
/* @__PURE__ */ jsx32("button", { onClick: () => setBulkConfirm(null), className: "text-muted-foreground hover:text-foreground transition-colors", children: /* @__PURE__ */ jsx32(X9, { className: "h-4 w-4" }) })
|
|
8099
|
+
] }),
|
|
8100
|
+
/* @__PURE__ */ jsx32("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsx32("p", { className: "text-sm text-muted-foreground", children: bulkConfirm === "selected" ? `Are you sure you want to delete ${selectedIds.length} selected record${selectedIds.length !== 1 ? "s" : ""}? This action cannot be undone.` : "Are you sure you want to delete all records? This action cannot be undone." }) }),
|
|
8101
|
+
/* @__PURE__ */ jsxs30("div", { className: "px-6 py-4 border-t border-border flex justify-end gap-2", children: [
|
|
8102
|
+
/* @__PURE__ */ jsx32(Button, { variant: "outline", size: "sm", onClick: () => setBulkConfirm(null), disabled: bulkLoading, children: "Cancel" }),
|
|
8103
|
+
/* @__PURE__ */ jsxs30(Button, { variant: "danger", size: "sm", disabled: bulkLoading, onClick: async () => {
|
|
8104
|
+
if (bulkConfirm === "selected") await execBulkDeleteSelected();
|
|
8105
|
+
else await execDeleteAll();
|
|
8106
|
+
setBulkConfirm(null);
|
|
8107
|
+
}, children: [
|
|
8108
|
+
bulkLoading && /* @__PURE__ */ jsx32(Loader22, { className: "h-3.5 w-3.5 mr-1.5 animate-spin" }),
|
|
8109
|
+
bulkLoading ? "Deleting\u2026" : "Delete"
|
|
8110
|
+
] })
|
|
8111
|
+
] })
|
|
8112
|
+
] })
|
|
8113
|
+
}
|
|
8114
|
+
),
|
|
8115
|
+
document.body
|
|
7870
8116
|
)
|
|
7871
8117
|
] });
|
|
7872
8118
|
}
|