@rufous/ui 0.1.67 → 0.1.69
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/DataGrid/DataGrid.cjs +114 -56
- package/dist/DataGrid/DataGrid.d.cts +1 -1
- package/dist/DataGrid/DataGrid.d.ts +1 -1
- package/dist/DataGrid/DataGrid.js +1 -1
- package/dist/DataGrid/index.cjs +114 -56
- package/dist/DataGrid/index.js +1 -1
- package/dist/DataGrid/types.d.cts +4 -2
- package/dist/DataGrid/types.d.ts +4 -2
- package/dist/Dialogs/BaseDialog.js +4 -4
- package/dist/Dialogs/index.js +4 -4
- package/dist/{chunk-IKG2B6JQ.js → chunk-LG4EJGMI.js} +114 -56
- package/dist/main.cjs +114 -56
- package/dist/main.js +7 -7
- package/package.json +1 -1
|
@@ -19,24 +19,38 @@ import {
|
|
|
19
19
|
Plus
|
|
20
20
|
} from "lucide-react";
|
|
21
21
|
function DataGrid({
|
|
22
|
-
columns:
|
|
22
|
+
columns: initialColumnsProp,
|
|
23
23
|
data,
|
|
24
24
|
actions,
|
|
25
25
|
pageSize: initialPageSize = 10,
|
|
26
26
|
pageSizeOptions = [5, 10, 25, 50],
|
|
27
27
|
title
|
|
28
28
|
}) {
|
|
29
|
-
const [
|
|
29
|
+
const [columnOverrides, setColumnOverrides] = useState({});
|
|
30
|
+
const resolvedColumns = useMemo(() => {
|
|
31
|
+
return initialColumnsProp.map((col) => {
|
|
32
|
+
const field = String(col.field || col.key || "");
|
|
33
|
+
const override = columnOverrides[field] || {};
|
|
34
|
+
return {
|
|
35
|
+
...col,
|
|
36
|
+
field,
|
|
37
|
+
headerName: col.headerName || col.header || "",
|
|
38
|
+
hidden: override.hidden !== void 0 ? override.hidden : col.hidden,
|
|
39
|
+
pinned: override.pinned !== void 0 ? override.pinned : col.pinned
|
|
40
|
+
};
|
|
41
|
+
});
|
|
42
|
+
}, [initialColumnsProp, columnOverrides]);
|
|
30
43
|
const [columnWidths, setColumnWidths] = useState(() => {
|
|
31
44
|
const widths = {};
|
|
32
|
-
|
|
45
|
+
initialColumnsProp.forEach((col) => {
|
|
46
|
+
const field = String(col.field || col.key || "");
|
|
33
47
|
const w = col.width || 200;
|
|
34
|
-
widths[
|
|
48
|
+
widths[field] = typeof w === "number" ? w : parseInt(w);
|
|
35
49
|
});
|
|
36
50
|
return widths;
|
|
37
51
|
});
|
|
38
52
|
const [pageSize, setPageSize] = useState(initialPageSize);
|
|
39
|
-
const [
|
|
53
|
+
const [sortField, setSortField] = useState(null);
|
|
40
54
|
const [sortDirection, setSortDirection] = useState(null);
|
|
41
55
|
const [filterText, setFilterText] = useState("");
|
|
42
56
|
const [currentPage, setCurrentPage] = useState(1);
|
|
@@ -49,14 +63,15 @@ function DataGrid({
|
|
|
49
63
|
const menuRef = useRef(null);
|
|
50
64
|
const [showManageColumns, setShowManageColumns] = useState(false);
|
|
51
65
|
const [showAdvancedFilter, setShowAdvancedFilter] = useState(false);
|
|
66
|
+
const initialFilterCol = String(initialColumnsProp[0]?.field || initialColumnsProp[0]?.key || "");
|
|
52
67
|
const [advancedFilters, setAdvancedFilters] = useState([
|
|
53
|
-
{ column:
|
|
68
|
+
{ column: initialFilterCol, operator: "contains", value: "", logic: "AND" }
|
|
54
69
|
]);
|
|
55
70
|
const [colSearch, setColSearch] = useState("");
|
|
56
71
|
useEffect(() => {
|
|
57
72
|
const handleMouseMove = (e) => {
|
|
58
73
|
if (!resizingColumn) return;
|
|
59
|
-
const col =
|
|
74
|
+
const col = resolvedColumns.find((c) => String(c.field) === resizingColumn);
|
|
60
75
|
const diff = e.clientX - startX;
|
|
61
76
|
const minW = col?.minWidth ? typeof col.minWidth === "number" ? col.minWidth : parseInt(col.minWidth) : 80;
|
|
62
77
|
const maxW = col?.maxWidth ? typeof col.maxWidth === "number" ? col.maxWidth : parseInt(col.maxWidth) : Infinity;
|
|
@@ -72,7 +87,7 @@ function DataGrid({
|
|
|
72
87
|
document.removeEventListener("mousemove", handleMouseMove);
|
|
73
88
|
document.removeEventListener("mouseup", handleMouseUp);
|
|
74
89
|
};
|
|
75
|
-
}, [resizingColumn, startX, startWidth,
|
|
90
|
+
}, [resizingColumn, startX, startWidth, resolvedColumns]);
|
|
76
91
|
useEffect(() => {
|
|
77
92
|
const handleClickOutside = (e) => {
|
|
78
93
|
if (menuRef.current && !menuRef.current.contains(e.target)) {
|
|
@@ -82,32 +97,55 @@ function DataGrid({
|
|
|
82
97
|
document.addEventListener("mousedown", handleClickOutside);
|
|
83
98
|
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
84
99
|
}, []);
|
|
85
|
-
|
|
100
|
+
useEffect(() => {
|
|
101
|
+
setColumnWidths((prev) => {
|
|
102
|
+
const next = { ...prev };
|
|
103
|
+
initialColumnsProp.forEach((col) => {
|
|
104
|
+
const field = String(col.field || col.key || "");
|
|
105
|
+
if (next[field] === void 0) {
|
|
106
|
+
const w = col.width || 200;
|
|
107
|
+
next[field] = typeof w === "number" ? w : parseInt(w);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
return next;
|
|
111
|
+
});
|
|
112
|
+
}, [initialColumnsProp]);
|
|
113
|
+
const handleSort = (fieldKey, dir) => {
|
|
86
114
|
if (dir !== void 0) {
|
|
87
|
-
|
|
115
|
+
setSortField(fieldKey);
|
|
88
116
|
setSortDirection(dir);
|
|
89
|
-
} else if (
|
|
117
|
+
} else if (sortField === fieldKey) {
|
|
90
118
|
if (sortDirection === "asc") setSortDirection("desc");
|
|
91
119
|
else {
|
|
92
|
-
|
|
120
|
+
setSortField(null);
|
|
93
121
|
setSortDirection(null);
|
|
94
122
|
}
|
|
95
123
|
} else {
|
|
96
|
-
|
|
124
|
+
setSortField(fieldKey);
|
|
97
125
|
setSortDirection("asc");
|
|
98
126
|
}
|
|
99
127
|
setActiveMenu(null);
|
|
100
128
|
};
|
|
101
|
-
const togglePin = (
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
129
|
+
const togglePin = (fieldKey, side) => {
|
|
130
|
+
setColumnOverrides((prev) => {
|
|
131
|
+
const current = prev[fieldKey] || {};
|
|
132
|
+
return {
|
|
133
|
+
...prev,
|
|
134
|
+
[fieldKey]: { ...current, pinned: current.pinned === side ? void 0 : side }
|
|
135
|
+
};
|
|
136
|
+
});
|
|
105
137
|
setActiveMenu(null);
|
|
106
138
|
};
|
|
107
|
-
const toggleHide = (
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
139
|
+
const toggleHide = (fieldKey) => {
|
|
140
|
+
setColumnOverrides((prev) => {
|
|
141
|
+
const current = prev[fieldKey] || {};
|
|
142
|
+
const col = resolvedColumns.find((c) => String(c.field) === fieldKey);
|
|
143
|
+
if (col?.hideable === false) return prev;
|
|
144
|
+
return {
|
|
145
|
+
...prev,
|
|
146
|
+
[fieldKey]: { ...current, hidden: !current.hidden }
|
|
147
|
+
};
|
|
148
|
+
});
|
|
111
149
|
setActiveMenu(null);
|
|
112
150
|
};
|
|
113
151
|
const filteredData = useMemo(() => {
|
|
@@ -149,30 +187,30 @@ function DataGrid({
|
|
|
149
187
|
});
|
|
150
188
|
}, [data, filterText, advancedFilters]);
|
|
151
189
|
const sortedData = useMemo(() => {
|
|
152
|
-
if (!
|
|
153
|
-
const col =
|
|
190
|
+
if (!sortField || !sortDirection) return filteredData;
|
|
191
|
+
const col = resolvedColumns.find((c) => c.field === sortField);
|
|
154
192
|
return [...filteredData].sort((a, b) => {
|
|
155
|
-
let aVal = a[
|
|
156
|
-
let bVal = b[
|
|
193
|
+
let aVal = a[sortField];
|
|
194
|
+
let bVal = b[sortField];
|
|
157
195
|
if (col?.valueGetter) {
|
|
158
|
-
aVal = col.valueGetter({ value: aVal, row: a, field: String(
|
|
159
|
-
bVal = col.valueGetter({ value: bVal, row: b, field: String(
|
|
196
|
+
aVal = col.valueGetter({ value: aVal, row: a, field: String(sortField) });
|
|
197
|
+
bVal = col.valueGetter({ value: bVal, row: b, field: String(sortField) });
|
|
160
198
|
}
|
|
161
199
|
if (aVal < bVal) return sortDirection === "asc" ? -1 : 1;
|
|
162
200
|
if (aVal > bVal) return sortDirection === "asc" ? 1 : -1;
|
|
163
201
|
return 0;
|
|
164
202
|
});
|
|
165
|
-
}, [filteredData,
|
|
203
|
+
}, [filteredData, sortField, sortDirection, resolvedColumns]);
|
|
166
204
|
const totalPages = Math.max(1, Math.ceil(sortedData.length / pageSize));
|
|
167
205
|
const paginatedData = useMemo(() => {
|
|
168
206
|
const start = (currentPage - 1) * pageSize;
|
|
169
207
|
return sortedData.slice(start, start + pageSize);
|
|
170
208
|
}, [sortedData, currentPage, pageSize]);
|
|
171
209
|
const handleExport = () => {
|
|
172
|
-
const visibleCols =
|
|
173
|
-
const headers = visibleCols.map((c) => c.
|
|
210
|
+
const visibleCols = resolvedColumns.filter((c) => !c.hidden);
|
|
211
|
+
const headers = visibleCols.map((c) => c.headerName).join(",");
|
|
174
212
|
const rows = sortedData.map(
|
|
175
|
-
(item) => visibleCols.map((c) => `"${String(item[c.
|
|
213
|
+
(item) => visibleCols.map((c) => `"${String(item[c.field]).replace(/"/g, '""')}"`).join(",")
|
|
176
214
|
);
|
|
177
215
|
const csv = [headers, ...rows].join("\n");
|
|
178
216
|
const blob = new Blob([csv], { type: "text/csv;charset=utf-8;" });
|
|
@@ -183,24 +221,24 @@ function DataGrid({
|
|
|
183
221
|
link.click();
|
|
184
222
|
document.body.removeChild(link);
|
|
185
223
|
};
|
|
186
|
-
const handleMenuOpen = (e,
|
|
224
|
+
const handleMenuOpen = (e, keyStr) => {
|
|
187
225
|
e.stopPropagation();
|
|
188
226
|
const rect = e.currentTarget.getBoundingClientRect();
|
|
189
227
|
setMenuPosition({ top: rect.bottom + 4, left: rect.left });
|
|
190
|
-
setActiveMenu(
|
|
228
|
+
setActiveMenu(keyStr);
|
|
191
229
|
};
|
|
192
230
|
const visibleColumns = useMemo(() => {
|
|
193
|
-
const left =
|
|
194
|
-
const mid =
|
|
195
|
-
const right =
|
|
231
|
+
const left = resolvedColumns.filter((c) => !c.hidden && c.pinned === "left");
|
|
232
|
+
const mid = resolvedColumns.filter((c) => !c.hidden && !c.pinned);
|
|
233
|
+
const right = resolvedColumns.filter((c) => !c.hidden && c.pinned === "right");
|
|
196
234
|
return [...left, ...mid, ...right];
|
|
197
|
-
}, [
|
|
235
|
+
}, [resolvedColumns]);
|
|
198
236
|
const getLeftOffset = (col, idx) => {
|
|
199
237
|
if (col.pinned !== "left") return void 0;
|
|
200
238
|
let offset = 0;
|
|
201
239
|
for (let i = 0; i < idx; i++) {
|
|
202
240
|
if (visibleColumns[i].pinned === "left") {
|
|
203
|
-
offset += columnWidths[String(visibleColumns[i].
|
|
241
|
+
offset += columnWidths[String(visibleColumns[i].field)] || 200;
|
|
204
242
|
}
|
|
205
243
|
}
|
|
206
244
|
return offset;
|
|
@@ -234,14 +272,14 @@ function DataGrid({
|
|
|
234
272
|
},
|
|
235
273
|
/* @__PURE__ */ React.createElement(Columns, { size: 16 })
|
|
236
274
|
), /* @__PURE__ */ React.createElement("button", { className: "dg-action-btn", onClick: handleExport }, /* @__PURE__ */ React.createElement(Download, { size: 14 }), " Export CSV"))), /* @__PURE__ */ React.createElement("div", { className: "dg-table-wrap" }, /* @__PURE__ */ React.createElement("table", { className: "dg-table" }, /* @__PURE__ */ React.createElement("thead", null, /* @__PURE__ */ React.createElement("tr", null, visibleColumns.map((col, idx) => {
|
|
237
|
-
const
|
|
238
|
-
const width = columnWidths[
|
|
275
|
+
const colField = String(col.field);
|
|
276
|
+
const width = columnWidths[colField] || 200;
|
|
239
277
|
const leftOffset = getLeftOffset(col, idx);
|
|
240
|
-
const isSorted =
|
|
278
|
+
const isSorted = sortField === col.field;
|
|
241
279
|
return /* @__PURE__ */ React.createElement(
|
|
242
280
|
"th",
|
|
243
281
|
{
|
|
244
|
-
key:
|
|
282
|
+
key: colField,
|
|
245
283
|
className: `dg-thead-cell${col.pinned === "left" ? " pinned-left" : col.pinned === "right" ? " pinned-right" : ""} ${col.headerClassName || ""}`,
|
|
246
284
|
style: { width, minWidth: width, left: leftOffset, flex: col.flex }
|
|
247
285
|
},
|
|
@@ -249,25 +287,25 @@ function DataGrid({
|
|
|
249
287
|
"div",
|
|
250
288
|
{
|
|
251
289
|
className: `dg-th-label${col.sortable === false ? " no-sort" : ""}`,
|
|
252
|
-
onClick: () => col.sortable !== false && handleSort(col.
|
|
290
|
+
onClick: () => col.sortable !== false && handleSort(col.field || "")
|
|
253
291
|
},
|
|
254
|
-
col.
|
|
292
|
+
col.headerName,
|
|
255
293
|
isSorted && sortDirection === "asc" && /* @__PURE__ */ React.createElement(ChevronUp, { size: 12 }),
|
|
256
294
|
isSorted && sortDirection === "desc" && /* @__PURE__ */ React.createElement(ChevronDown, { size: 12 })
|
|
257
295
|
), /* @__PURE__ */ React.createElement("div", { className: "dg-th-actions" }, !col.disableColumnMenu && /* @__PURE__ */ React.createElement(
|
|
258
296
|
"button",
|
|
259
297
|
{
|
|
260
298
|
className: "dg-th-menu-btn",
|
|
261
|
-
onClick: (e) => handleMenuOpen(e,
|
|
299
|
+
onClick: (e) => handleMenuOpen(e, colField)
|
|
262
300
|
},
|
|
263
301
|
/* @__PURE__ */ React.createElement(MoreVertical, { size: 13 })
|
|
264
302
|
), /* @__PURE__ */ React.createElement(
|
|
265
303
|
"div",
|
|
266
304
|
{
|
|
267
|
-
className: `dg-resizer${resizingColumn ===
|
|
305
|
+
className: `dg-resizer${resizingColumn === colField ? " resizing" : ""}`,
|
|
268
306
|
onMouseDown: (e) => {
|
|
269
307
|
e.preventDefault();
|
|
270
|
-
setResizingColumn(
|
|
308
|
+
setResizingColumn(colField);
|
|
271
309
|
setStartX(e.clientX);
|
|
272
310
|
setStartWidth(width);
|
|
273
311
|
}
|
|
@@ -275,19 +313,19 @@ function DataGrid({
|
|
|
275
313
|
)))
|
|
276
314
|
);
|
|
277
315
|
}), actions && /* @__PURE__ */ React.createElement("th", { style: { width: 0, padding: 0 } }))), /* @__PURE__ */ React.createElement("tbody", null, paginatedData.length === 0 ? /* @__PURE__ */ React.createElement("tr", null, /* @__PURE__ */ React.createElement("td", { colSpan: visibleColumns.length + (actions ? 1 : 0), className: "dg-empty" }, "No records found")) : paginatedData.map((item) => /* @__PURE__ */ React.createElement("tr", { key: item.id, className: "dg-tbody-row" }, visibleColumns.map((col, idx) => {
|
|
278
|
-
const
|
|
279
|
-
const width = columnWidths[
|
|
316
|
+
const colField = String(col.field);
|
|
317
|
+
const width = columnWidths[colField] || 200;
|
|
280
318
|
const leftOffset = getLeftOffset(col, idx);
|
|
281
319
|
return /* @__PURE__ */ React.createElement(
|
|
282
320
|
"td",
|
|
283
321
|
{
|
|
284
|
-
key: `${item.id}-${
|
|
322
|
+
key: `${item.id}-${colField}`,
|
|
285
323
|
className: `dg-td${col.pinned === "left" ? " pinned-left" : ""} ${col.cellClassName || ""}`,
|
|
286
324
|
style: { width, minWidth: width, maxWidth: width, left: leftOffset, flex: col.flex }
|
|
287
325
|
},
|
|
288
326
|
(() => {
|
|
289
|
-
const field = String(col.
|
|
290
|
-
const rawValue = item[col.
|
|
327
|
+
const field = String(col.field);
|
|
328
|
+
const rawValue = item[col.field || ""];
|
|
291
329
|
let value = col.valueGetter ? col.valueGetter({ value: rawValue, row: item, field }) : rawValue;
|
|
292
330
|
const formattedValue = col.valueFormatter ? col.valueFormatter({ value, row: item, field }) : value;
|
|
293
331
|
if (col.renderCell) {
|
|
@@ -355,7 +393,27 @@ function DataGrid({
|
|
|
355
393
|
value: colSearch,
|
|
356
394
|
onChange: (e) => setColSearch(e.target.value)
|
|
357
395
|
}
|
|
358
|
-
)),
|
|
396
|
+
)), resolvedColumns.filter((c) => c.header.toLowerCase().includes(colSearch.toLowerCase())).map((col) => {
|
|
397
|
+
const key = String(col.key);
|
|
398
|
+
const isUnhideable = col.hideable === false;
|
|
399
|
+
return /* @__PURE__ */ React.createElement("div", { key, className: `dg-col-row${isUnhideable ? " disabled" : ""}` }, /* @__PURE__ */ React.createElement("div", { className: "dg-col-label" }, /* @__PURE__ */ React.createElement("div", { className: "dg-col-dot", style: { background: col.hidden ? "var(--border-color)" : "var(--primary-color)" } }), col.header), !isUnhideable && /* @__PURE__ */ React.createElement("button", { className: "dg-icon-btn", onClick: () => toggleHide(key) }, col.hidden ? /* @__PURE__ */ React.createElement(EyeOff, { size: 14 }) : /* @__PURE__ */ React.createElement(EyeOff, { size: 14, style: { opacity: 0.4 } })));
|
|
400
|
+
})), /* @__PURE__ */ React.createElement("div", { className: "dg-modal-footer" }, /* @__PURE__ */ React.createElement("button", { className: "dg-action-btn", onClick: () => setColumnOverrides((prev) => {
|
|
401
|
+
const next = { ...prev };
|
|
402
|
+
resolvedColumns.forEach((c) => {
|
|
403
|
+
const k = String(c.key);
|
|
404
|
+
next[k] = { ...next[k], hidden: false };
|
|
405
|
+
});
|
|
406
|
+
return next;
|
|
407
|
+
}) }, "Show All"), /* @__PURE__ */ React.createElement("button", { className: "dg-action-btn", onClick: () => {
|
|
408
|
+
const newOverrides = { ...columnOverrides };
|
|
409
|
+
resolvedColumns.forEach((c) => {
|
|
410
|
+
if (c.hideable !== false) {
|
|
411
|
+
const key = String(c.key);
|
|
412
|
+
newOverrides[key] = { ...newOverrides[key], hidden: true };
|
|
413
|
+
}
|
|
414
|
+
});
|
|
415
|
+
setColumnOverrides(newOverrides);
|
|
416
|
+
} }, "Hide All")))), showAdvancedFilter && /* @__PURE__ */ React.createElement("div", { className: "dg-modal-overlay", onClick: () => setShowAdvancedFilter(false) }, /* @__PURE__ */ React.createElement("div", { className: "dg-modal dg-modal-wide", onClick: (e) => e.stopPropagation() }, /* @__PURE__ */ React.createElement("div", { className: "dg-modal-header" }, /* @__PURE__ */ React.createElement("h3", null, "Filters"), /* @__PURE__ */ React.createElement("button", { className: "dg-icon-btn", onClick: () => setShowAdvancedFilter(false) }, /* @__PURE__ */ React.createElement(X, { size: 18 }))), /* @__PURE__ */ React.createElement("div", { className: "dg-modal-body" }, advancedFilters.map((f, idx) => /* @__PURE__ */ React.createElement("div", { key: idx }, idx > 0 && /* @__PURE__ */ React.createElement("div", { className: "dg-filter-logic" }, /* @__PURE__ */ React.createElement(
|
|
359
417
|
"button",
|
|
360
418
|
{
|
|
361
419
|
className: `dg-logic-btn${f.logic === "AND" ? " active" : ""}`,
|
|
@@ -376,7 +434,7 @@ function DataGrid({
|
|
|
376
434
|
value: f.column,
|
|
377
435
|
onChange: (e) => setAdvancedFilters((p) => p.map((fi, i) => i === idx ? { ...fi, column: e.target.value } : fi))
|
|
378
436
|
},
|
|
379
|
-
|
|
437
|
+
resolvedColumns.map((c) => /* @__PURE__ */ React.createElement("option", { key: String(c.key), value: String(c.key) }, c.header))
|
|
380
438
|
), /* @__PURE__ */ React.createElement(
|
|
381
439
|
"select",
|
|
382
440
|
{
|
|
@@ -403,7 +461,7 @@ function DataGrid({
|
|
|
403
461
|
{
|
|
404
462
|
className: "dg-action-btn",
|
|
405
463
|
style: { alignSelf: "flex-start", marginTop: 4 },
|
|
406
|
-
onClick: () => setAdvancedFilters((p) => [...p, { column: String(
|
|
464
|
+
onClick: () => setAdvancedFilters((p) => [...p, { column: String(resolvedColumns[0].key), operator: "contains", value: "", logic: "AND" }])
|
|
407
465
|
},
|
|
408
466
|
/* @__PURE__ */ React.createElement(Plus, { size: 14 }),
|
|
409
467
|
" Add Filter"
|
|
@@ -411,7 +469,7 @@ function DataGrid({
|
|
|
411
469
|
"button",
|
|
412
470
|
{
|
|
413
471
|
className: "dg-action-btn",
|
|
414
|
-
onClick: () => setAdvancedFilters([{ column: String(
|
|
472
|
+
onClick: () => setAdvancedFilters([{ column: String(resolvedColumns[0].key), operator: "contains", value: "", logic: "AND" }])
|
|
415
473
|
},
|
|
416
474
|
/* @__PURE__ */ React.createElement(Trash2, { size: 14 }),
|
|
417
475
|
" Reset"
|