@juv/codego-react-ui 3.4.7 → 3.4.8
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 +443 -117
- package/dist/index.d.cts +73 -21
- package/dist/index.d.ts +73 -21
- package/dist/index.global.js +500 -161
- package/dist/index.js +477 -151
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -5906,11 +5906,77 @@ function FileUpload({
|
|
|
5906
5906
|
// src/components/ui/repeater.tsx
|
|
5907
5907
|
var import_lucide_react15 = require("lucide-react");
|
|
5908
5908
|
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
5909
|
+
function RepeaterFieldRenderer({
|
|
5910
|
+
field,
|
|
5911
|
+
value,
|
|
5912
|
+
onChange
|
|
5913
|
+
}) {
|
|
5914
|
+
if (field.type === "image") {
|
|
5915
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex flex-col gap-1.5", children: [
|
|
5916
|
+
field.label && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "text-xs font-medium text-muted-foreground", children: field.label }),
|
|
5917
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex items-center gap-3", children: [
|
|
5918
|
+
value && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("img", { src: value, alt: field.key, className: "h-10 w-10 rounded-lg object-cover ring-1 ring-border shrink-0" }),
|
|
5919
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
5920
|
+
Input,
|
|
5921
|
+
{
|
|
5922
|
+
inputMode: "text",
|
|
5923
|
+
value: value ?? "",
|
|
5924
|
+
onChange: (e) => onChange(e.target.value),
|
|
5925
|
+
placeholder: field.placeholder ?? "Image URL"
|
|
5926
|
+
}
|
|
5927
|
+
)
|
|
5928
|
+
] })
|
|
5929
|
+
] });
|
|
5930
|
+
}
|
|
5931
|
+
if (field.type === "attachment") {
|
|
5932
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex flex-col gap-1.5", children: [
|
|
5933
|
+
field.label && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "text-xs font-medium text-muted-foreground", children: field.label }),
|
|
5934
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
5935
|
+
value && /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
|
|
5936
|
+
"a",
|
|
5937
|
+
{
|
|
5938
|
+
href: value,
|
|
5939
|
+
target: "_blank",
|
|
5940
|
+
rel: "noopener noreferrer",
|
|
5941
|
+
className: "inline-flex items-center gap-1.5 rounded-lg border border-border bg-muted/50 px-2.5 py-1 text-xs font-medium text-foreground hover:bg-muted transition-colors shrink-0",
|
|
5942
|
+
children: [
|
|
5943
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_lucide_react15.Paperclip, { className: "h-3 w-3" }),
|
|
5944
|
+
String(value).split("/").pop()
|
|
5945
|
+
]
|
|
5946
|
+
}
|
|
5947
|
+
),
|
|
5948
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
5949
|
+
Input,
|
|
5950
|
+
{
|
|
5951
|
+
inputMode: "text",
|
|
5952
|
+
value: value ?? "",
|
|
5953
|
+
onChange: (e) => onChange(e.target.value),
|
|
5954
|
+
placeholder: field.placeholder ?? "Attachment URL"
|
|
5955
|
+
}
|
|
5956
|
+
)
|
|
5957
|
+
] })
|
|
5958
|
+
] });
|
|
5959
|
+
}
|
|
5960
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex flex-col gap-1.5", children: [
|
|
5961
|
+
field.label && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "text-xs font-medium text-muted-foreground", children: field.label }),
|
|
5962
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
5963
|
+
Input,
|
|
5964
|
+
{
|
|
5965
|
+
inputMode: "text",
|
|
5966
|
+
value: value ?? "",
|
|
5967
|
+
onChange: (e) => onChange(e.target.value),
|
|
5968
|
+
placeholder: field.placeholder ?? field.key
|
|
5969
|
+
}
|
|
5970
|
+
)
|
|
5971
|
+
] });
|
|
5972
|
+
}
|
|
5909
5973
|
function Repeater({
|
|
5910
5974
|
items,
|
|
5911
5975
|
onAdd,
|
|
5912
5976
|
onRemove,
|
|
5913
5977
|
renderItem,
|
|
5978
|
+
fields,
|
|
5979
|
+
onFieldChange,
|
|
5914
5980
|
addButtonText = "Add Item",
|
|
5915
5981
|
className
|
|
5916
5982
|
}) {
|
|
@@ -5923,7 +5989,15 @@ function Repeater({
|
|
|
5923
5989
|
children: [
|
|
5924
5990
|
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "mt-1 cursor-grab text-muted-foreground/30 group-hover:text-muted-foreground/60 transition-colors shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_lucide_react15.GripVertical, { className: "h-4 w-4" }) }),
|
|
5925
5991
|
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "mt-1 flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-primary/10 text-[10px] font-semibold text-primary", children: index + 1 }),
|
|
5926
|
-
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "flex-1 min-w-0", children:
|
|
5992
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "flex-1 min-w-0", children: fields ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "grid gap-3", style: { gridTemplateColumns: fields.length > 1 ? `repeat(${Math.min(fields.length, 3)}, minmax(0, 1fr))` : "1fr" }, children: fields.map((f) => /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
5993
|
+
RepeaterFieldRenderer,
|
|
5994
|
+
{
|
|
5995
|
+
field: f,
|
|
5996
|
+
value: item[f.key],
|
|
5997
|
+
onChange: (v) => onFieldChange?.(index, f.key, v)
|
|
5998
|
+
},
|
|
5999
|
+
f.key
|
|
6000
|
+
)) }) : renderItem ? renderItem(item, index) : null }),
|
|
5927
6001
|
/* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
|
|
5928
6002
|
Button,
|
|
5929
6003
|
{
|
|
@@ -6496,8 +6570,14 @@ function useServerTable({ url, params, encrypt, key, decryptPayloadLog, columnOv
|
|
|
6496
6570
|
goToPage: (page) => setCurrentPage(page),
|
|
6497
6571
|
reload: () => setTick((t) => t + 1),
|
|
6498
6572
|
refresh: () => setTick((t) => t + 1),
|
|
6573
|
+
// Passthrough props
|
|
6499
6574
|
searchValue,
|
|
6500
|
-
onSearchChange: handleSearchChange
|
|
6575
|
+
onSearchChange: handleSearchChange,
|
|
6576
|
+
page: currentPage,
|
|
6577
|
+
onPageChange: (page) => setCurrentPage(page),
|
|
6578
|
+
sort: [],
|
|
6579
|
+
onSortChange: () => {
|
|
6580
|
+
}
|
|
6501
6581
|
};
|
|
6502
6582
|
}
|
|
6503
6583
|
var MODAL_WIDTH = {
|
|
@@ -6653,6 +6733,28 @@ function FieldRenderer({ field, value, onChange }) {
|
|
|
6653
6733
|
} });
|
|
6654
6734
|
case "repeater": {
|
|
6655
6735
|
const items = Array.isArray(value) ? value : [];
|
|
6736
|
+
if (field.repeaterFields) {
|
|
6737
|
+
const rows = Array.isArray(value) ? value : [];
|
|
6738
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
6739
|
+
Repeater,
|
|
6740
|
+
{
|
|
6741
|
+
items: rows,
|
|
6742
|
+
fields: field.repeaterFields,
|
|
6743
|
+
onAdd: () => {
|
|
6744
|
+
const blank = {};
|
|
6745
|
+
field.repeaterFields.forEach((f) => {
|
|
6746
|
+
blank[f.key] = "";
|
|
6747
|
+
});
|
|
6748
|
+
onChange([...rows, blank]);
|
|
6749
|
+
},
|
|
6750
|
+
onRemove: (i) => onChange(rows.filter((_, idx) => idx !== i)),
|
|
6751
|
+
onFieldChange: (i, key, val) => {
|
|
6752
|
+
const next = rows.map((r, idx) => idx === i ? { ...r, [key]: val } : r);
|
|
6753
|
+
onChange(next);
|
|
6754
|
+
}
|
|
6755
|
+
}
|
|
6756
|
+
);
|
|
6757
|
+
}
|
|
6656
6758
|
return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
6657
6759
|
Repeater,
|
|
6658
6760
|
{
|
|
@@ -6779,6 +6881,47 @@ function ViewModal({
|
|
|
6779
6881
|
]
|
|
6780
6882
|
}
|
|
6781
6883
|
);
|
|
6884
|
+
case "repeater": {
|
|
6885
|
+
const rows = Array.isArray(value) ? value : [];
|
|
6886
|
+
if (!rows.length) return dash;
|
|
6887
|
+
const rFields = f.repeaterFields;
|
|
6888
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: "space-y-2", children: rows.map((row, ri) => /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "flex flex-wrap gap-3 rounded-xl border border-border bg-muted/30 px-3 py-2", children: [
|
|
6889
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-primary/10 text-[10px] font-semibold text-primary", children: ri + 1 }),
|
|
6890
|
+
rFields ? rFields.map((rf) => {
|
|
6891
|
+
const v = row[rf.key];
|
|
6892
|
+
if (rf.type === "image") return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "flex flex-col gap-1", children: [
|
|
6893
|
+
rf.label && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "text-[10px] text-muted-foreground", children: rf.label }),
|
|
6894
|
+
v ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("img", { src: v, alt: rf.key, className: "h-10 w-10 rounded-lg object-cover ring-1 ring-border" }) : dash
|
|
6895
|
+
] }, rf.key);
|
|
6896
|
+
if (rf.type === "attachment") return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "flex flex-col gap-1", children: [
|
|
6897
|
+
rf.label && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "text-[10px] text-muted-foreground", children: rf.label }),
|
|
6898
|
+
v ? /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
|
|
6899
|
+
"a",
|
|
6900
|
+
{
|
|
6901
|
+
href: v,
|
|
6902
|
+
target: "_blank",
|
|
6903
|
+
rel: "noopener noreferrer",
|
|
6904
|
+
className: "inline-flex items-center gap-1 rounded-lg border border-border bg-muted/50 px-2 py-1 text-xs font-medium hover:bg-muted transition-colors",
|
|
6905
|
+
children: [
|
|
6906
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("svg", { className: "h-3 w-3 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M15.172 7l-6.586 6.586a2 2 0 102.828 2.828l6.414-6.586a4 4 0 00-5.656-5.656l-6.415 6.585a6 6 0 108.486 8.486L20.5 13" }) }),
|
|
6907
|
+
String(v).split("/").pop()
|
|
6908
|
+
]
|
|
6909
|
+
}
|
|
6910
|
+
) : dash
|
|
6911
|
+
] }, rf.key);
|
|
6912
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "flex flex-col gap-1", children: [
|
|
6913
|
+
rf.label && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "text-[10px] text-muted-foreground", children: rf.label }),
|
|
6914
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "text-sm", children: v ?? "\u2014" })
|
|
6915
|
+
] }, rf.key);
|
|
6916
|
+
}) : (
|
|
6917
|
+
// payload mode: row has { type, key, value }
|
|
6918
|
+
Object.entries(row).map(([k, v]) => /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "flex flex-col gap-1", children: [
|
|
6919
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "text-[10px] text-muted-foreground", children: k }),
|
|
6920
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "text-sm", children: String(v) })
|
|
6921
|
+
] }, k))
|
|
6922
|
+
)
|
|
6923
|
+
] }, ri)) });
|
|
6924
|
+
}
|
|
6782
6925
|
case "checkbox":
|
|
6783
6926
|
return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
6784
6927
|
"input",
|
|
@@ -7078,12 +7221,45 @@ var BADGE_COLORS = {
|
|
|
7078
7221
|
function badgeClass(value) {
|
|
7079
7222
|
return BADGE_COLORS[value.toLowerCase()] ?? "bg-primary/10 text-primary border-primary/20";
|
|
7080
7223
|
}
|
|
7224
|
+
function deriveField(key, sample) {
|
|
7225
|
+
const label = key.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
7226
|
+
const base = { key, label };
|
|
7227
|
+
if (typeof sample === "boolean") return { ...base, type: "toggle", viewType: "toggle" };
|
|
7228
|
+
if (typeof sample === "number") return { ...base, inputType: "number" };
|
|
7229
|
+
if (Array.isArray(sample)) {
|
|
7230
|
+
if (sample.length === 0 || typeof sample[0] === "string")
|
|
7231
|
+
return { ...base, type: "tag-input" };
|
|
7232
|
+
return base;
|
|
7233
|
+
}
|
|
7234
|
+
if (typeof sample === "string") {
|
|
7235
|
+
if (/\.(png|jpe?g|gif|webp|svg|avif)(\?.*)?$/i.test(sample))
|
|
7236
|
+
return { ...base, type: "input", viewType: "image" };
|
|
7237
|
+
if (/\.(pdf|docx?|xlsx?|csv|zip|pptx?)(\?.*)?$/i.test(sample))
|
|
7238
|
+
return { ...base, type: "input", viewType: "attachment" };
|
|
7239
|
+
if (/^https?:\/\//.test(sample))
|
|
7240
|
+
return { ...base, type: "input", viewType: "text-url-open-other-tabs" };
|
|
7241
|
+
if (sample.length > 120 || /\n/.test(sample))
|
|
7242
|
+
return { ...base, type: "textarea" };
|
|
7243
|
+
if (/password|secret|token/i.test(key))
|
|
7244
|
+
return { ...base, type: "password" };
|
|
7245
|
+
if (/email/i.test(key))
|
|
7246
|
+
return { ...base, inputType: "email" };
|
|
7247
|
+
if (/color|colour/i.test(key) && /^#[0-9a-f]{3,8}$/i.test(sample))
|
|
7248
|
+
return { ...base, type: "color-picker", viewType: "text" };
|
|
7249
|
+
}
|
|
7250
|
+
return base;
|
|
7251
|
+
}
|
|
7081
7252
|
function Table({
|
|
7082
7253
|
data,
|
|
7083
7254
|
columns,
|
|
7255
|
+
loading,
|
|
7256
|
+
emptyState,
|
|
7257
|
+
error: errorProp,
|
|
7084
7258
|
searchable = false,
|
|
7085
7259
|
searchPlaceholder = "Search...",
|
|
7086
|
-
|
|
7260
|
+
searchValue: controlledSearch,
|
|
7261
|
+
onSearchChange,
|
|
7262
|
+
clientPagination = false,
|
|
7087
7263
|
itemsPerPage = 10,
|
|
7088
7264
|
selectable = false,
|
|
7089
7265
|
onBulkDelete,
|
|
@@ -7091,15 +7267,38 @@ function Table({
|
|
|
7091
7267
|
bulkDeleteBaseUrl,
|
|
7092
7268
|
defaultActions,
|
|
7093
7269
|
serverPagination,
|
|
7094
|
-
|
|
7270
|
+
variant = "default",
|
|
7271
|
+
className,
|
|
7272
|
+
onRowClick,
|
|
7273
|
+
onRowDoubleClick,
|
|
7274
|
+
rowClassName,
|
|
7275
|
+
expandable = false,
|
|
7276
|
+
renderExpanded,
|
|
7277
|
+
columnVisibility,
|
|
7278
|
+
onColumnVisibilityChange,
|
|
7279
|
+
exportable = false,
|
|
7280
|
+
onExport,
|
|
7281
|
+
virtualized = false,
|
|
7282
|
+
draggable = false,
|
|
7283
|
+
onRowReorder,
|
|
7284
|
+
keyboardNavigation = false
|
|
7095
7285
|
}) {
|
|
7096
7286
|
const { toast } = useToast();
|
|
7097
|
-
const
|
|
7287
|
+
const isControlledSearch = controlledSearch !== void 0;
|
|
7288
|
+
const [internalSearch, setInternalSearch] = React28.useState("");
|
|
7289
|
+
const search = isControlledSearch ? controlledSearch : internalSearch;
|
|
7290
|
+
const setSearch = (v) => {
|
|
7291
|
+
if (!isControlledSearch) setInternalSearch(v);
|
|
7292
|
+
onSearchChange?.(v);
|
|
7293
|
+
};
|
|
7098
7294
|
const [currentPage, setCurrentPage] = React28.useState(1);
|
|
7099
7295
|
const [selectedIds, setSelectedIds] = React28.useState([]);
|
|
7100
7296
|
const [sortKey, setSortKey] = React28.useState(null);
|
|
7101
7297
|
const [sortDir, setSortDir] = React28.useState(null);
|
|
7102
7298
|
const [bulkLoading, setBulkLoading] = React28.useState(false);
|
|
7299
|
+
const [expandedIds, setExpandedIds] = React28.useState(/* @__PURE__ */ new Set());
|
|
7300
|
+
const [dragOverId, setDragOverId] = React28.useState(null);
|
|
7301
|
+
const [focusedRowIdx, setFocusedRowIdx] = React28.useState(-1);
|
|
7103
7302
|
const [viewItem, setViewItem] = React28.useState(null);
|
|
7104
7303
|
const [editItem, setEditItem] = React28.useState(null);
|
|
7105
7304
|
const [deleteItem, setDeleteItem] = React28.useState(null);
|
|
@@ -7111,15 +7310,17 @@ function Table({
|
|
|
7111
7310
|
const safeBaseUrl = defaultActions?.baseUrl.replace(/\/+$/, "") ?? "";
|
|
7112
7311
|
const autoFields = React28.useMemo(() => {
|
|
7113
7312
|
if (!tableData.length) return [];
|
|
7114
|
-
|
|
7115
|
-
|
|
7116
|
-
label: k.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase())
|
|
7117
|
-
}));
|
|
7313
|
+
const row = tableData[0];
|
|
7314
|
+
return Object.keys(row).map((k) => deriveField(k, row[k]));
|
|
7118
7315
|
}, [tableData]);
|
|
7119
7316
|
const editFields = defaultActions?.editForm ?? autoFields;
|
|
7120
7317
|
const viewFields = defaultActions?.viewForm ?? autoFields;
|
|
7318
|
+
const visibleColumns = React28.useMemo(() => {
|
|
7319
|
+
if (!columnVisibility) return columns;
|
|
7320
|
+
return columns.filter((col) => columnVisibility[String(col.key)] !== false);
|
|
7321
|
+
}, [columns, columnVisibility]);
|
|
7121
7322
|
const allColumns = React28.useMemo(() => {
|
|
7122
|
-
if (!defaultActions) return
|
|
7323
|
+
if (!defaultActions) return visibleColumns;
|
|
7123
7324
|
const actionsCol = {
|
|
7124
7325
|
key: "__actions__",
|
|
7125
7326
|
title: "Actions",
|
|
@@ -7168,8 +7369,8 @@ function Table({
|
|
|
7168
7369
|
))
|
|
7169
7370
|
] })
|
|
7170
7371
|
};
|
|
7171
|
-
return defaultActions.position === "first" ? [actionsCol, ...
|
|
7172
|
-
}, [
|
|
7372
|
+
return defaultActions.position === "first" ? [actionsCol, ...visibleColumns] : [...visibleColumns, actionsCol];
|
|
7373
|
+
}, [visibleColumns, defaultActions]);
|
|
7173
7374
|
const handleSort = (key) => {
|
|
7174
7375
|
if (sortKey !== key) {
|
|
7175
7376
|
setSortKey(key);
|
|
@@ -7202,13 +7403,28 @@ function Table({
|
|
|
7202
7403
|
const totalPages = Math.max(1, Math.ceil(filteredData.length / itemsPerPage));
|
|
7203
7404
|
const safePage = Math.min(currentPage, totalPages);
|
|
7204
7405
|
const paginatedData = React28.useMemo(() => {
|
|
7205
|
-
if (!
|
|
7406
|
+
if (!clientPagination) return filteredData;
|
|
7206
7407
|
const start = (safePage - 1) * itemsPerPage;
|
|
7207
7408
|
return filteredData.slice(start, start + itemsPerPage);
|
|
7208
|
-
}, [filteredData,
|
|
7409
|
+
}, [filteredData, clientPagination, safePage, itemsPerPage]);
|
|
7209
7410
|
React28.useEffect(() => {
|
|
7210
7411
|
setCurrentPage(1);
|
|
7211
7412
|
}, [search]);
|
|
7413
|
+
React28.useEffect(() => {
|
|
7414
|
+
if (!keyboardNavigation) return;
|
|
7415
|
+
const handler = (e) => {
|
|
7416
|
+
if (e.key === "ArrowDown") {
|
|
7417
|
+
e.preventDefault();
|
|
7418
|
+
setFocusedRowIdx((i) => Math.min(i + 1, paginatedData.length - 1));
|
|
7419
|
+
}
|
|
7420
|
+
if (e.key === "ArrowUp") {
|
|
7421
|
+
e.preventDefault();
|
|
7422
|
+
setFocusedRowIdx((i) => Math.max(i - 1, 0));
|
|
7423
|
+
}
|
|
7424
|
+
};
|
|
7425
|
+
window.addEventListener("keydown", handler);
|
|
7426
|
+
return () => window.removeEventListener("keydown", handler);
|
|
7427
|
+
}, [keyboardNavigation, paginatedData.length]);
|
|
7212
7428
|
const handleSelectAll = (checked) => setSelectedIds(checked ? paginatedData.map((item) => String(item[idKey])) : []);
|
|
7213
7429
|
const handleSelect = (id, checked) => setSelectedIds((prev) => checked ? [...prev, id] : prev.filter((i) => i !== id));
|
|
7214
7430
|
const allSelected = paginatedData.length > 0 && selectedIds.length === paginatedData.length;
|
|
@@ -7268,6 +7484,7 @@ function Table({
|
|
|
7268
7484
|
};
|
|
7269
7485
|
return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(import_jsx_runtime32.Fragment, { children: [
|
|
7270
7486
|
/* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: cn("w-full space-y-3", className), children: [
|
|
7487
|
+
errorProp && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: "rounded-xl border border-danger/30 bg-danger/5 px-4 py-3 text-sm text-danger", children: errorProp }),
|
|
7271
7488
|
/* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "flex items-center justify-between gap-3 flex-wrap", children: [
|
|
7272
7489
|
searchable && /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "relative w-72", children: [
|
|
7273
7490
|
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_lucide_react17.Search, { className: "absolute text-primary left-3 top-1/2 -translate-y-1/2 h-4 w-4 z-10" }),
|
|
@@ -7343,6 +7560,33 @@ function Table({
|
|
|
7343
7560
|
]
|
|
7344
7561
|
}
|
|
7345
7562
|
),
|
|
7563
|
+
exportable && /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "relative group", children: [
|
|
7564
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("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: "Export" }),
|
|
7565
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: "absolute right-0 top-full mt-1 z-20 hidden group-hover:flex flex-col min-w-[110px] rounded-xl border border-border bg-card shadow-lg overflow-hidden", children: ["csv", "excel", "pdf"].map((type) => /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
7566
|
+
"button",
|
|
7567
|
+
{
|
|
7568
|
+
onClick: () => onExport?.(type),
|
|
7569
|
+
className: "px-4 py-2 text-xs text-left hover:bg-muted transition-colors capitalize",
|
|
7570
|
+
children: type.toUpperCase()
|
|
7571
|
+
},
|
|
7572
|
+
type
|
|
7573
|
+
)) })
|
|
7574
|
+
] }),
|
|
7575
|
+
columnVisibility && onColumnVisibilityChange && /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "relative group", children: [
|
|
7576
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("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" }),
|
|
7577
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("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__ */ (0, import_jsx_runtime32.jsxs)("label", { className: "flex items-center gap-2 px-2 py-1 rounded-lg hover:bg-muted cursor-pointer text-xs", children: [
|
|
7578
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
7579
|
+
"input",
|
|
7580
|
+
{
|
|
7581
|
+
type: "checkbox",
|
|
7582
|
+
checked: columnVisibility[String(col.key)] !== false,
|
|
7583
|
+
onChange: (e) => onColumnVisibilityChange({ ...columnVisibility, [String(col.key)]: e.target.checked }),
|
|
7584
|
+
className: "accent-primary"
|
|
7585
|
+
}
|
|
7586
|
+
),
|
|
7587
|
+
col.title
|
|
7588
|
+
] }, String(col.key))) })
|
|
7589
|
+
] }),
|
|
7346
7590
|
/* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("span", { className: "text-xs text-muted-foreground", children: [
|
|
7347
7591
|
totalRows,
|
|
7348
7592
|
" ",
|
|
@@ -7351,8 +7595,26 @@ function Table({
|
|
|
7351
7595
|
] })
|
|
7352
7596
|
] })
|
|
7353
7597
|
] }),
|
|
7354
|
-
/* @__PURE__ */ (0, import_jsx_runtime32.
|
|
7355
|
-
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
7598
|
+
loading && /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "flex items-center justify-center py-12 text-muted-foreground gap-2", children: [
|
|
7599
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_lucide_react17.Loader2, { className: "h-5 w-5 animate-spin" }),
|
|
7600
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "text-sm", children: "Loading\u2026" })
|
|
7601
|
+
] }),
|
|
7602
|
+
!loading && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: cn(
|
|
7603
|
+
variant === "default" && "rounded-xl border border-border overflow-hidden bg-card/50 backdrop-blur-sm shadow-sm",
|
|
7604
|
+
variant === "zebra" && "rounded-xl border border-border overflow-hidden bg-card/50 backdrop-blur-sm shadow-sm",
|
|
7605
|
+
variant === "card" && "space-y-2",
|
|
7606
|
+
variant === "glass" && "rounded-2xl overflow-hidden border border-white/10 bg-background/30 backdrop-blur-xl shadow-xl",
|
|
7607
|
+
variant === "soft" && "rounded-2xl overflow-hidden bg-card",
|
|
7608
|
+
variant === "soft" && "[box-shadow:6px_6px_12px_hsl(var(--foreground)/0.07),-6px_-6px_12px_hsl(var(--background)/0.8)]",
|
|
7609
|
+
virtualized && "max-h-[520px] overflow-y-auto"
|
|
7610
|
+
), children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: cn("w-full overflow-auto", variant === "card" && "space-y-2"), children: /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("table", { className: cn("w-full caption-bottom text-sm", variant === "card" && "border-separate border-spacing-y-2"), children: [
|
|
7611
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("tr", { className: cn(
|
|
7612
|
+
variant === "default" && "border-b border-border bg-muted/40",
|
|
7613
|
+
variant === "zebra" && "border-b border-border bg-muted/40",
|
|
7614
|
+
variant === "card" && "[&>th]:bg-transparent",
|
|
7615
|
+
variant === "glass" && "border-b border-white/10 bg-white/5",
|
|
7616
|
+
variant === "soft" && "border-b-0 bg-muted/30"
|
|
7617
|
+
), children: [
|
|
7356
7618
|
selectable && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("th", { className: "h-11 w-[46px] px-4 text-left align-middle", children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
7357
7619
|
Checkbox,
|
|
7358
7620
|
{
|
|
@@ -7360,13 +7622,16 @@ function Table({
|
|
|
7360
7622
|
onChange: (e) => handleSelectAll(e.target.checked)
|
|
7361
7623
|
}
|
|
7362
7624
|
) }),
|
|
7625
|
+
expandable && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("th", { className: "h-11 w-8" }),
|
|
7363
7626
|
allColumns.map((col, ci) => /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
7364
7627
|
"th",
|
|
7365
7628
|
{
|
|
7366
7629
|
onClick: () => col.sortable && handleSort(String(col.key)),
|
|
7367
7630
|
className: cn(
|
|
7368
7631
|
"h-11 px-4 text-left align-middle text-xs font-semibold uppercase tracking-wider text-muted-foreground select-none whitespace-nowrap",
|
|
7369
|
-
col.sortable && "cursor-pointer hover:text-foreground transition-colors"
|
|
7632
|
+
col.sortable && "cursor-pointer hover:text-foreground transition-colors",
|
|
7633
|
+
variant === "glass" && "text-foreground/70",
|
|
7634
|
+
variant === "soft" && "text-muted-foreground/80"
|
|
7370
7635
|
),
|
|
7371
7636
|
children: /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("span", { className: "inline-flex items-center", children: [
|
|
7372
7637
|
col.title,
|
|
@@ -7379,9 +7644,9 @@ function Table({
|
|
|
7379
7644
|
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("tbody", { children: paginatedData.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
7380
7645
|
"td",
|
|
7381
7646
|
{
|
|
7382
|
-
colSpan: allColumns.length + (selectable ? 1 : 0),
|
|
7647
|
+
colSpan: allColumns.length + (selectable ? 1 : 0) + (expandable ? 1 : 0),
|
|
7383
7648
|
className: "h-32 text-center align-middle",
|
|
7384
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "flex flex-col items-center gap-1 text-muted-foreground", children: [
|
|
7649
|
+
children: emptyState ?? /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "flex flex-col items-center gap-1 text-muted-foreground", children: [
|
|
7385
7650
|
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_lucide_react17.Search, { className: "h-8 w-8 opacity-20" }),
|
|
7386
7651
|
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "text-sm", children: "No results found" }),
|
|
7387
7652
|
search && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("button", { onClick: () => setSearch(""), className: "text-xs text-primary hover:underline", children: "Clear search" })
|
|
@@ -7390,107 +7655,168 @@ function Table({
|
|
|
7390
7655
|
) }) : paginatedData.map((item, i) => {
|
|
7391
7656
|
const id = String(item[idKey] || i);
|
|
7392
7657
|
const isSelected = selectedIds.includes(id);
|
|
7393
|
-
|
|
7394
|
-
|
|
7395
|
-
|
|
7396
|
-
|
|
7397
|
-
|
|
7398
|
-
|
|
7399
|
-
|
|
7400
|
-
|
|
7401
|
-
|
|
7402
|
-
|
|
7403
|
-
|
|
7404
|
-
|
|
7405
|
-
|
|
7406
|
-
|
|
7407
|
-
|
|
7408
|
-
|
|
7409
|
-
|
|
7410
|
-
|
|
7411
|
-
|
|
7412
|
-
|
|
7413
|
-
|
|
7414
|
-
|
|
7415
|
-
|
|
7416
|
-
|
|
7417
|
-
|
|
7418
|
-
|
|
7419
|
-
|
|
7420
|
-
|
|
7421
|
-
|
|
7658
|
+
const isExpanded = expandedIds.has(id);
|
|
7659
|
+
const isFocused = keyboardNavigation && focusedRowIdx === i;
|
|
7660
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(React28.Fragment, { children: [
|
|
7661
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
|
|
7662
|
+
"tr",
|
|
7663
|
+
{
|
|
7664
|
+
draggable,
|
|
7665
|
+
tabIndex: keyboardNavigation ? 0 : void 0,
|
|
7666
|
+
onDragStart: draggable ? (e) => {
|
|
7667
|
+
e.dataTransfer.setData("text/plain", id);
|
|
7668
|
+
} : void 0,
|
|
7669
|
+
onDragOver: draggable ? (e) => {
|
|
7670
|
+
e.preventDefault();
|
|
7671
|
+
setDragOverId(id);
|
|
7672
|
+
} : void 0,
|
|
7673
|
+
onDragLeave: draggable ? () => setDragOverId(null) : void 0,
|
|
7674
|
+
onDrop: draggable ? (e) => {
|
|
7675
|
+
e.preventDefault();
|
|
7676
|
+
setDragOverId(null);
|
|
7677
|
+
const fromId = e.dataTransfer.getData("text/plain");
|
|
7678
|
+
if (fromId === id) return;
|
|
7679
|
+
setTableData((prev) => {
|
|
7680
|
+
const fromIdx = prev.findIndex((r) => String(r[idKey] || "") === fromId);
|
|
7681
|
+
const toIdx = prev.findIndex((r) => String(r[idKey] || "") === id);
|
|
7682
|
+
if (fromIdx < 0 || toIdx < 0) return prev;
|
|
7683
|
+
const next = [...prev];
|
|
7684
|
+
const [moved] = next.splice(fromIdx, 1);
|
|
7685
|
+
next.splice(toIdx, 0, moved);
|
|
7686
|
+
onRowReorder?.(next);
|
|
7687
|
+
return next;
|
|
7688
|
+
});
|
|
7689
|
+
} : void 0,
|
|
7690
|
+
onClick: () => {
|
|
7691
|
+
if (expandable) setExpandedIds((prev) => {
|
|
7692
|
+
const s = new Set(prev);
|
|
7693
|
+
s.has(id) ? s.delete(id) : s.add(id);
|
|
7694
|
+
return s;
|
|
7695
|
+
});
|
|
7696
|
+
onRowClick?.(item);
|
|
7697
|
+
if (keyboardNavigation) setFocusedRowIdx(i);
|
|
7698
|
+
},
|
|
7699
|
+
onDoubleClick: () => onRowDoubleClick?.(item),
|
|
7700
|
+
className: cn(
|
|
7701
|
+
// default
|
|
7702
|
+
variant === "default" && "border-b border-border/60 transition-colors last:border-0",
|
|
7703
|
+
variant === "default" && (isSelected ? "bg-primary/5 hover:bg-primary/8" : "hover:bg-muted/30"),
|
|
7704
|
+
// zebra
|
|
7705
|
+
variant === "zebra" && "border-b border-border/40 transition-colors last:border-0",
|
|
7706
|
+
variant === "zebra" && (isSelected ? "bg-primary/8" : i % 2 === 0 ? "bg-card" : "bg-muted/40"),
|
|
7707
|
+
variant === "zebra" && !isSelected && "hover:bg-primary/5",
|
|
7708
|
+
// card
|
|
7709
|
+
variant === "card" && "rounded-xl border border-border bg-card shadow-sm transition-all hover:shadow-md hover:-translate-y-px",
|
|
7710
|
+
variant === "card" && (isSelected ? "border-primary/50 bg-primary/5" : ""),
|
|
7711
|
+
variant === "card" && "[&>td:first-child]:rounded-l-xl [&>td:last-child]:rounded-r-xl",
|
|
7712
|
+
// glass
|
|
7713
|
+
variant === "glass" && "border-b border-white/8 transition-colors last:border-0",
|
|
7714
|
+
variant === "glass" && (isSelected ? "bg-primary/15 hover:bg-primary/20" : "hover:bg-white/5"),
|
|
7715
|
+
// soft
|
|
7716
|
+
variant === "soft" && "transition-all",
|
|
7717
|
+
variant === "soft" && (isSelected ? "bg-primary/8 [box-shadow:inset_2px_2px_5px_hsl(var(--foreground)/0.06),inset_-2px_-2px_5px_hsl(var(--background)/0.7)]" : "hover:bg-muted/20"),
|
|
7718
|
+
variant === "soft" && "border-b border-border/30 last:border-0",
|
|
7719
|
+
(onRowClick || onRowDoubleClick || expandable) && "cursor-pointer",
|
|
7720
|
+
draggable && dragOverId === id && "ring-2 ring-inset ring-primary/40",
|
|
7721
|
+
isFocused && "ring-2 ring-inset ring-ring",
|
|
7722
|
+
rowClassName?.(item)
|
|
7723
|
+
),
|
|
7724
|
+
children: [
|
|
7725
|
+
selectable && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("td", { className: "px-4 py-3 align-middle", children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
7726
|
+
Checkbox,
|
|
7727
|
+
{
|
|
7728
|
+
checked: isSelected,
|
|
7729
|
+
onChange: (e) => handleSelect(id, e.target.checked)
|
|
7730
|
+
}
|
|
7422
7731
|
) }),
|
|
7423
|
-
|
|
7424
|
-
|
|
7425
|
-
|
|
7426
|
-
{
|
|
7427
|
-
value: item[col.key],
|
|
7428
|
-
onChange: (e) => col.onChange?.(item, e.target.value),
|
|
7429
|
-
className: "h-8 rounded-lg border border-border bg-background/50 px-2 text-xs text-foreground focus:outline-none focus:ring-2 focus:ring-ring transition-colors",
|
|
7430
|
-
children: (col.selectOptions ?? []).map((opt) => /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("option", { value: opt, children: opt }, opt))
|
|
7431
|
-
}
|
|
7432
|
-
) : col.type === "toggle" ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
7433
|
-
"button",
|
|
7434
|
-
{
|
|
7435
|
-
role: "switch",
|
|
7436
|
-
"aria-checked": !!item[col.key],
|
|
7437
|
-
onClick: () => col.onChange?.(item, !item[col.key]),
|
|
7438
|
-
className: cn(
|
|
7439
|
-
"relative inline-flex h-5 w-9 shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
|
|
7440
|
-
item[col.key] ? "bg-primary" : "bg-muted"
|
|
7441
|
-
),
|
|
7442
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: cn(
|
|
7443
|
-
"pointer-events-none inline-block h-4 w-4 rounded-full bg-white shadow-sm transition-transform",
|
|
7444
|
-
item[col.key] ? "translate-x-4" : "translate-x-0"
|
|
7445
|
-
) })
|
|
7446
|
-
}
|
|
7447
|
-
) : col.type === "color" ? /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
7448
|
-
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
7449
|
-
"input",
|
|
7732
|
+
expandable && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("td", { className: "w-8 px-2 py-3 align-middle", children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_lucide_react17.ChevronRight, { className: cn("h-3.5 w-3.5 text-muted-foreground transition-transform", isExpanded && "rotate-90") }) }),
|
|
7733
|
+
allColumns.map((col, ci) => /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("td", { className: "px-4 py-3 align-middle", children: col.render ? col.render(item) : col.type === "image" ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
7734
|
+
"img",
|
|
7450
7735
|
{
|
|
7451
|
-
|
|
7452
|
-
|
|
7736
|
+
src: item[col.key],
|
|
7737
|
+
alt: item[col.key],
|
|
7738
|
+
className: "h-9 w-9 rounded-lg object-cover ring-1 ring-border"
|
|
7739
|
+
}
|
|
7740
|
+
) : col.type === "badge" ? /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("span", { className: cn(
|
|
7741
|
+
"inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-medium",
|
|
7742
|
+
badgeClass(String(item[col.key]))
|
|
7743
|
+
), children: [
|
|
7744
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: cn(
|
|
7745
|
+
"mr-1.5 h-1.5 w-1.5 rounded-full",
|
|
7746
|
+
badgeClass(String(item[col.key])).includes("success") ? "bg-success" : badgeClass(String(item[col.key])).includes("warning") ? "bg-warning" : badgeClass(String(item[col.key])).includes("danger") ? "bg-danger" : badgeClass(String(item[col.key])).includes("info") ? "bg-info" : "bg-primary"
|
|
7747
|
+
) }),
|
|
7748
|
+
item[col.key]
|
|
7749
|
+
] }) : col.type === "stack" ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(AvatarStack, { images: Array.isArray(item[col.key]) ? item[col.key] : [], ...col.stackProps ?? {} }) : col.type === "icon" ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "flex items-center", children: item[col.key] }) : col.type === "select" ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
7750
|
+
"select",
|
|
7751
|
+
{
|
|
7752
|
+
value: item[col.key],
|
|
7453
7753
|
onChange: (e) => col.onChange?.(item, e.target.value),
|
|
7454
|
-
className: "h-
|
|
7754
|
+
className: "h-8 rounded-lg border border-border bg-background/50 px-2 text-xs text-foreground focus:outline-none focus:ring-2 focus:ring-ring transition-colors",
|
|
7755
|
+
children: (col.selectOptions ?? []).map((opt) => /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("option", { value: opt, children: opt }, opt))
|
|
7455
7756
|
}
|
|
7456
|
-
),
|
|
7457
|
-
|
|
7458
|
-
] }) : col.type === "checkbox" ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
7459
|
-
Checkbox,
|
|
7460
|
-
{
|
|
7461
|
-
checked: !!item[col.key],
|
|
7462
|
-
onChange: (e) => col.onChange?.(item, e.target.checked)
|
|
7463
|
-
}
|
|
7464
|
-
) : col.type === "text-url" ? (() => {
|
|
7465
|
-
const href = col.redirect ? typeof col.redirect === "function" ? col.redirect(item) : col.redirect : String(item[col.key] ?? "");
|
|
7466
|
-
const colorMap = {
|
|
7467
|
-
primary: "var(--primary)",
|
|
7468
|
-
info: "var(--info)",
|
|
7469
|
-
success: "var(--success)",
|
|
7470
|
-
warning: "var(--warning)",
|
|
7471
|
-
danger: "var(--danger)"
|
|
7472
|
-
};
|
|
7473
|
-
const underline = col.underlineColor ? colorMap[col.underlineColor] ?? col.underlineColor : "var(--primary)";
|
|
7474
|
-
return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
7475
|
-
"a",
|
|
7757
|
+
) : col.type === "toggle" ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
7758
|
+
"button",
|
|
7476
7759
|
{
|
|
7477
|
-
|
|
7478
|
-
|
|
7479
|
-
|
|
7480
|
-
|
|
7481
|
-
|
|
7482
|
-
|
|
7483
|
-
|
|
7760
|
+
role: "switch",
|
|
7761
|
+
"aria-checked": !!item[col.key],
|
|
7762
|
+
onClick: () => col.onChange?.(item, !item[col.key]),
|
|
7763
|
+
className: cn(
|
|
7764
|
+
"relative inline-flex h-5 w-9 shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
|
|
7765
|
+
item[col.key] ? "bg-primary" : "bg-muted"
|
|
7766
|
+
),
|
|
7767
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: cn(
|
|
7768
|
+
"pointer-events-none inline-block h-4 w-4 rounded-full bg-white shadow-sm transition-transform",
|
|
7769
|
+
item[col.key] ? "translate-x-4" : "translate-x-0"
|
|
7770
|
+
) })
|
|
7484
7771
|
}
|
|
7485
|
-
)
|
|
7486
|
-
|
|
7487
|
-
|
|
7488
|
-
|
|
7489
|
-
|
|
7490
|
-
|
|
7772
|
+
) : col.type === "color" ? /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
7773
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
7774
|
+
"input",
|
|
7775
|
+
{
|
|
7776
|
+
type: "color",
|
|
7777
|
+
value: item[col.key] || "#000000",
|
|
7778
|
+
onChange: (e) => col.onChange?.(item, e.target.value),
|
|
7779
|
+
className: "h-7 w-7 cursor-pointer rounded border border-border bg-transparent p-0.5"
|
|
7780
|
+
}
|
|
7781
|
+
),
|
|
7782
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "text-xs text-muted-foreground font-mono", children: item[col.key] })
|
|
7783
|
+
] }) : col.type === "checkbox" ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
7784
|
+
Checkbox,
|
|
7785
|
+
{
|
|
7786
|
+
checked: !!item[col.key],
|
|
7787
|
+
onChange: (e) => col.onChange?.(item, e.target.checked)
|
|
7788
|
+
}
|
|
7789
|
+
) : col.type === "text-url" ? (() => {
|
|
7790
|
+
const href = col.redirect ? typeof col.redirect === "function" ? col.redirect(item) : col.redirect : String(item[col.key] ?? "");
|
|
7791
|
+
const colorMap = {
|
|
7792
|
+
primary: "var(--primary)",
|
|
7793
|
+
info: "var(--info)",
|
|
7794
|
+
success: "var(--success)",
|
|
7795
|
+
warning: "var(--warning)",
|
|
7796
|
+
danger: "var(--danger)"
|
|
7797
|
+
};
|
|
7798
|
+
const underline = col.underlineColor ? colorMap[col.underlineColor] ?? col.underlineColor : "var(--primary)";
|
|
7799
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
7800
|
+
"a",
|
|
7801
|
+
{
|
|
7802
|
+
href,
|
|
7803
|
+
target: col.openNewTab ? "_blank" : void 0,
|
|
7804
|
+
rel: col.openNewTab ? "noopener noreferrer" : void 0,
|
|
7805
|
+
style: { textDecorationColor: underline },
|
|
7806
|
+
className: "text-sm underline underline-offset-2 hover:opacity-75 transition-opacity break-all",
|
|
7807
|
+
onClick: col.openNewTab ? void 0 : (e) => e.preventDefault(),
|
|
7808
|
+
children: item[col.key]
|
|
7809
|
+
}
|
|
7810
|
+
);
|
|
7811
|
+
})() : /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "text-foreground/90", children: item[col.key] }) }, `${String(col.key)}-${ci}`))
|
|
7812
|
+
]
|
|
7813
|
+
}
|
|
7814
|
+
),
|
|
7815
|
+
expandable && isExpanded && renderExpanded && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("tr", { className: "bg-muted/20 border-b border-border/60", children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("td", { colSpan: allColumns.length + (selectable ? 1 : 0) + 1, className: "px-6 py-3", children: renderExpanded(item) }) })
|
|
7816
|
+
] }, id);
|
|
7491
7817
|
}) })
|
|
7492
7818
|
] }) }) }),
|
|
7493
|
-
|
|
7819
|
+
clientPagination && !serverPagination && totalPages > 1 && /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "flex items-center justify-between gap-2 flex-wrap", children: [
|
|
7494
7820
|
/* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("span", { className: "text-xs text-muted-foreground", children: [
|
|
7495
7821
|
"Showing ",
|
|
7496
7822
|
(safePage - 1) * itemsPerPage + 1,
|
|
@@ -7541,8 +7867,8 @@ function Table({
|
|
|
7541
7867
|
] })
|
|
7542
7868
|
] }),
|
|
7543
7869
|
serverPagination && (() => {
|
|
7544
|
-
const { pagination
|
|
7545
|
-
const totalServerPages =
|
|
7870
|
+
const { pagination, currentPage: cp, goToPage } = serverPagination;
|
|
7871
|
+
const totalServerPages = pagination.last_page ?? Math.ceil(pagination.total / pagination.per_page);
|
|
7546
7872
|
const pills = [];
|
|
7547
7873
|
if (totalServerPages <= 7) {
|
|
7548
7874
|
for (let i = 1; i <= totalServerPages; i++) pills.push(i);
|
|
@@ -7555,7 +7881,7 @@ function Table({
|
|
|
7555
7881
|
}
|
|
7556
7882
|
return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "flex items-center justify-between gap-2 flex-wrap", children: [
|
|
7557
7883
|
/* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("span", { className: "text-xs text-muted-foreground", children: [
|
|
7558
|
-
|
|
7884
|
+
pagination.total,
|
|
7559
7885
|
" total rows \xB7 page ",
|
|
7560
7886
|
cp,
|
|
7561
7887
|
" of ",
|
|
@@ -7566,7 +7892,7 @@ function Table({
|
|
|
7566
7892
|
"button",
|
|
7567
7893
|
{
|
|
7568
7894
|
onClick: () => goToPage(cp - 1),
|
|
7569
|
-
disabled: !
|
|
7895
|
+
disabled: !pagination.prev_page_url,
|
|
7570
7896
|
className: "flex h-8 w-8 items-center justify-center rounded-lg border border-border text-muted-foreground transition-colors hover:bg-muted hover:text-foreground disabled:opacity-40 disabled:pointer-events-none",
|
|
7571
7897
|
children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_lucide_react17.ChevronLeft, { className: "h-4 w-4" })
|
|
7572
7898
|
}
|
|
@@ -7589,7 +7915,7 @@ function Table({
|
|
|
7589
7915
|
"button",
|
|
7590
7916
|
{
|
|
7591
7917
|
onClick: () => goToPage(cp + 1),
|
|
7592
|
-
disabled: !
|
|
7918
|
+
disabled: !pagination.next_page_url,
|
|
7593
7919
|
className: "flex h-8 w-8 items-center justify-center rounded-lg border border-border text-muted-foreground transition-colors hover:bg-muted hover:text-foreground disabled:opacity-40 disabled:pointer-events-none",
|
|
7594
7920
|
children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_lucide_react17.ChevronRight, { className: "h-4 w-4" })
|
|
7595
7921
|
}
|