@rufous/ui 0.3.23 → 0.3.24
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/main.cjs +363 -86
- package/dist/main.css +153 -1
- package/dist/main.d.cts +144 -2
- package/dist/main.d.ts +144 -2
- package/dist/main.js +365 -87
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -4472,8 +4472,57 @@ import {
|
|
|
4472
4472
|
ArrowDown,
|
|
4473
4473
|
Trash2,
|
|
4474
4474
|
Plus,
|
|
4475
|
-
ChevronsUpDown
|
|
4475
|
+
ChevronsUpDown,
|
|
4476
|
+
Layers
|
|
4476
4477
|
} from "lucide-react";
|
|
4478
|
+
function getAllGroupIds(rows, fields, getKey, depth = 0, parentId = "") {
|
|
4479
|
+
if (!fields.length || !rows.length) return [];
|
|
4480
|
+
const [field, ...rest] = fields;
|
|
4481
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
4482
|
+
rows.forEach((row) => {
|
|
4483
|
+
const k = getKey(row, field) || "(Blank)";
|
|
4484
|
+
if (!buckets.has(k)) buckets.set(k, []);
|
|
4485
|
+
buckets.get(k).push(row);
|
|
4486
|
+
});
|
|
4487
|
+
const out = [];
|
|
4488
|
+
buckets.forEach((children, k) => {
|
|
4489
|
+
const id = `${parentId}::${field}::${k}`;
|
|
4490
|
+
out.push({ id, field, key: k, depth, count: children.length });
|
|
4491
|
+
if (rest.length) out.push(...getAllGroupIds(children, rest, getKey, depth + 1, id));
|
|
4492
|
+
});
|
|
4493
|
+
return out;
|
|
4494
|
+
}
|
|
4495
|
+
function buildFlatEntries(rows, fields, getKey, expanded, depth = 0, parentId = "") {
|
|
4496
|
+
if (!fields.length) return rows.map((row) => ({ kind: "data", row, depth }));
|
|
4497
|
+
const [field, ...rest] = fields;
|
|
4498
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
4499
|
+
rows.forEach((row) => {
|
|
4500
|
+
const k = getKey(row, field) || "(Blank)";
|
|
4501
|
+
if (!buckets.has(k)) buckets.set(k, []);
|
|
4502
|
+
buckets.get(k).push(row);
|
|
4503
|
+
});
|
|
4504
|
+
const out = [];
|
|
4505
|
+
buckets.forEach((children, k) => {
|
|
4506
|
+
const id = `${parentId}::${field}::${k}`;
|
|
4507
|
+
out.push({ kind: "group", id, field, key: k, depth, leafCount: children.length });
|
|
4508
|
+
if (expanded.has(id)) {
|
|
4509
|
+
out.push(...buildFlatEntries(children, rest, getKey, expanded, depth + 1, id));
|
|
4510
|
+
}
|
|
4511
|
+
});
|
|
4512
|
+
return out;
|
|
4513
|
+
}
|
|
4514
|
+
function buildTreeEntries(rows, getChildren, expanded, depth = 0) {
|
|
4515
|
+
const out = [];
|
|
4516
|
+
rows.forEach((row) => {
|
|
4517
|
+
const children = getChildren(row) ?? [];
|
|
4518
|
+
const hasChildren = children.length > 0;
|
|
4519
|
+
out.push({ kind: "data", row, depth, hasChildren });
|
|
4520
|
+
if (hasChildren && expanded.has(row.id)) {
|
|
4521
|
+
out.push(...buildTreeEntries(children, getChildren, expanded, depth + 1));
|
|
4522
|
+
}
|
|
4523
|
+
});
|
|
4524
|
+
return out;
|
|
4525
|
+
}
|
|
4477
4526
|
function FilterSelect({
|
|
4478
4527
|
value,
|
|
4479
4528
|
onChange,
|
|
@@ -4571,7 +4620,21 @@ function DataGrid({
|
|
|
4571
4620
|
searchableColumns,
|
|
4572
4621
|
onSearchChange,
|
|
4573
4622
|
onFiltersChange,
|
|
4574
|
-
|
|
4623
|
+
initialFilters,
|
|
4624
|
+
toolbarOptions,
|
|
4625
|
+
customToolbar,
|
|
4626
|
+
customFooter,
|
|
4627
|
+
hideTopExport = false,
|
|
4628
|
+
rowGroupingModel,
|
|
4629
|
+
defaultRowGroupingModel,
|
|
4630
|
+
onRowGroupingModelChange,
|
|
4631
|
+
rowGroupingColumnMode = "single",
|
|
4632
|
+
groupingColDef,
|
|
4633
|
+
defaultGroupingExpansionDepth = 0,
|
|
4634
|
+
isGroupExpandedByDefault,
|
|
4635
|
+
disableRowGrouping = false,
|
|
4636
|
+
treeData = false,
|
|
4637
|
+
getChildRows
|
|
4575
4638
|
}) {
|
|
4576
4639
|
const sxClass = useSx(sx);
|
|
4577
4640
|
const [editingCell, setEditingCell] = useState9(null);
|
|
@@ -4631,10 +4694,46 @@ function DataGrid({
|
|
|
4631
4694
|
const [focusFilterIdx, setFocusFilterIdx] = useState9(-1);
|
|
4632
4695
|
const filterableColumnsProp = initialColumnsProp.filter((c) => c.filterable !== false);
|
|
4633
4696
|
const initialFilterCol = String(filterableColumnsProp[0]?.field || filterableColumnsProp[0]?.key || "");
|
|
4634
|
-
const [advancedFilters, setAdvancedFilters] = useState9(
|
|
4635
|
-
|
|
4636
|
-
|
|
4697
|
+
const [advancedFilters, setAdvancedFilters] = useState9(() => {
|
|
4698
|
+
if (initialFilters && initialFilters.length > 0) return initialFilters;
|
|
4699
|
+
return [{ column: initialFilterCol, operator: getDefaultOperator(filterableColumnsProp[0]?.type), value: "", logic: "AND" }];
|
|
4700
|
+
});
|
|
4637
4701
|
const [colSearch, setColSearch] = useState9("");
|
|
4702
|
+
const [internalGroupingModel, setInternalGroupingModel] = useState9(
|
|
4703
|
+
defaultRowGroupingModel ?? []
|
|
4704
|
+
);
|
|
4705
|
+
const activeGroupingModel = rowGroupingModel ?? internalGroupingModel;
|
|
4706
|
+
const isGroupingActive = activeGroupingModel.length > 0;
|
|
4707
|
+
const setGroupingModel = (model) => {
|
|
4708
|
+
if (!rowGroupingModel) setInternalGroupingModel(model);
|
|
4709
|
+
onRowGroupingModelChange?.(model);
|
|
4710
|
+
};
|
|
4711
|
+
const addToGrouping = (field) => {
|
|
4712
|
+
if (activeGroupingModel.includes(field)) return;
|
|
4713
|
+
setGroupingModel([...activeGroupingModel, field]);
|
|
4714
|
+
};
|
|
4715
|
+
const removeFromGrouping = (field) => {
|
|
4716
|
+
setGroupingModel(activeGroupingModel.filter((f) => f !== field));
|
|
4717
|
+
};
|
|
4718
|
+
const [expandedGroups, setExpandedGroups] = useState9(/* @__PURE__ */ new Set());
|
|
4719
|
+
const prevGroupModelKeyRef = useRef10("");
|
|
4720
|
+
const toggleGroup = (groupId) => {
|
|
4721
|
+
setExpandedGroups((prev) => {
|
|
4722
|
+
const next = new Set(prev);
|
|
4723
|
+
if (next.has(groupId)) next.delete(groupId);
|
|
4724
|
+
else next.add(groupId);
|
|
4725
|
+
return next;
|
|
4726
|
+
});
|
|
4727
|
+
};
|
|
4728
|
+
const [treeExpandedRows, setTreeExpandedRows] = useState9(/* @__PURE__ */ new Set());
|
|
4729
|
+
const toggleTreeRow = (id) => {
|
|
4730
|
+
setTreeExpandedRows((prev) => {
|
|
4731
|
+
const next = new Set(prev);
|
|
4732
|
+
if (next.has(id)) next.delete(id);
|
|
4733
|
+
else next.add(id);
|
|
4734
|
+
return next;
|
|
4735
|
+
});
|
|
4736
|
+
};
|
|
4638
4737
|
useEffect9(() => {
|
|
4639
4738
|
const handleMouseMove = (e) => {
|
|
4640
4739
|
if (!resizingColumn) return;
|
|
@@ -4677,6 +4776,13 @@ function DataGrid({
|
|
|
4677
4776
|
return next;
|
|
4678
4777
|
});
|
|
4679
4778
|
}, [initialColumnsProp]);
|
|
4779
|
+
const getGroupValue = (item, field) => {
|
|
4780
|
+
const col = resolvedColumns.find((c) => String(c.field) === field || String(c.key) === field);
|
|
4781
|
+
const raw = item[field];
|
|
4782
|
+
if (col?.groupingValueGetter) return String(col.groupingValueGetter(raw, item) ?? "");
|
|
4783
|
+
if (col?.valueGetter) return String(col.valueGetter({ value: raw, row: item, field }) ?? "");
|
|
4784
|
+
return raw == null ? "" : String(raw);
|
|
4785
|
+
};
|
|
4680
4786
|
const onFiltersChangeRef = useRef10(onFiltersChange);
|
|
4681
4787
|
useEffect9(() => {
|
|
4682
4788
|
onFiltersChangeRef.current = onFiltersChange;
|
|
@@ -4864,14 +4970,36 @@ function DataGrid({
|
|
|
4864
4970
|
return 0;
|
|
4865
4971
|
});
|
|
4866
4972
|
}, [filteredData, sortField, sortDirection, resolvedColumns]);
|
|
4973
|
+
useEffect9(() => {
|
|
4974
|
+
const key = activeGroupingModel.join("\0");
|
|
4975
|
+
if (key === prevGroupModelKeyRef.current) return;
|
|
4976
|
+
prevGroupModelKeyRef.current = key;
|
|
4977
|
+
if (!activeGroupingModel.length) {
|
|
4978
|
+
setExpandedGroups(/* @__PURE__ */ new Set());
|
|
4979
|
+
return;
|
|
4980
|
+
}
|
|
4981
|
+
const allGroups = getAllGroupIds(sortedData, activeGroupingModel, getGroupValue);
|
|
4982
|
+
setExpandedGroups(new Set(
|
|
4983
|
+
allGroups.filter((g) => isGroupExpandedByDefault ? isGroupExpandedByDefault({ id: g.id, field: g.field, key: g.key, depth: g.depth, count: g.count }) : defaultGroupingExpansionDepth === -1 || g.depth < defaultGroupingExpansionDepth).map((g) => g.id)
|
|
4984
|
+
));
|
|
4985
|
+
}, [activeGroupingModel.join("\0")]);
|
|
4986
|
+
const resolveChildren = getChildRows ?? ((row) => row.children ?? null);
|
|
4987
|
+
const flatEntries = useMemo2(() => {
|
|
4988
|
+
if (treeData) {
|
|
4989
|
+
return buildTreeEntries(sortedData, resolveChildren, treeExpandedRows);
|
|
4990
|
+
}
|
|
4991
|
+
if (!isGroupingActive) return null;
|
|
4992
|
+
return buildFlatEntries(sortedData, activeGroupingModel, getGroupValue, expandedGroups);
|
|
4993
|
+
}, [treeData, isGroupingActive, sortedData, activeGroupingModel.join("\0"), expandedGroups, treeExpandedRows]);
|
|
4867
4994
|
const isServer = paginationMode === "server";
|
|
4868
|
-
const totalRows = isServer ? rowCount ?? data.length : filteredData.length;
|
|
4995
|
+
const totalRows = isServer ? rowCount ?? data.length : flatEntries ? flatEntries.length : filteredData.length;
|
|
4869
4996
|
const totalPages = Math.max(1, Math.ceil(totalRows / activePageSize));
|
|
4870
|
-
const
|
|
4871
|
-
if (isServer) return data;
|
|
4997
|
+
const displayRows = useMemo2(() => {
|
|
4998
|
+
if (isServer) return data.map((row) => ({ kind: "data", row, depth: 0 }));
|
|
4999
|
+
const source = flatEntries ?? sortedData.map((row) => ({ kind: "data", row, depth: 0 }));
|
|
4872
5000
|
const start = (activePage - 1) * activePageSize;
|
|
4873
|
-
return
|
|
4874
|
-
}, [isServer, data, sortedData, activePage, activePageSize]);
|
|
5001
|
+
return source.slice(start, start + activePageSize);
|
|
5002
|
+
}, [isServer, data, flatEntries, sortedData, activePage, activePageSize]);
|
|
4875
5003
|
const handleExport = () => {
|
|
4876
5004
|
const exportableCols = resolvedColumns.filter((c) => !c.hidden && c.isExportable !== false);
|
|
4877
5005
|
const headers = exportableCols.map((c) => c.headerName).join(",");
|
|
@@ -4921,8 +5049,57 @@ function DataGrid({
|
|
|
4921
5049
|
const left = resolvedColumns.filter((c) => !c.hidden && c.pinned === "left");
|
|
4922
5050
|
const mid = resolvedColumns.filter((c) => !c.hidden && !c.pinned);
|
|
4923
5051
|
const right = resolvedColumns.filter((c) => !c.hidden && c.pinned === "right");
|
|
4924
|
-
|
|
4925
|
-
|
|
5052
|
+
const dataCols = [...left, ...mid, ...right];
|
|
5053
|
+
if (treeData) {
|
|
5054
|
+
const treeCol = {
|
|
5055
|
+
key: "__tree__",
|
|
5056
|
+
field: "__tree__",
|
|
5057
|
+
header: "",
|
|
5058
|
+
headerName: "",
|
|
5059
|
+
width: 44,
|
|
5060
|
+
sortable: false,
|
|
5061
|
+
filterable: false,
|
|
5062
|
+
disableColumnMenu: true,
|
|
5063
|
+
hideable: false
|
|
5064
|
+
};
|
|
5065
|
+
return [treeCol, ...dataCols];
|
|
5066
|
+
}
|
|
5067
|
+
if (!isGroupingActive) return dataCols;
|
|
5068
|
+
if (rowGroupingColumnMode === "multiple") {
|
|
5069
|
+
const groupCols = activeGroupingModel.map((gField, i) => {
|
|
5070
|
+
const src = resolvedColumns.find((c) => String(c.field) === gField || String(c.key) === gField);
|
|
5071
|
+
const def2 = typeof groupingColDef === "function" ? groupingColDef(gField) : groupingColDef;
|
|
5072
|
+
return {
|
|
5073
|
+
key: `__group_${i}__`,
|
|
5074
|
+
field: `__group_${i}__`,
|
|
5075
|
+
header: def2?.headerName ?? src?.header ?? src?.headerName ?? gField,
|
|
5076
|
+
headerName: def2?.headerName ?? src?.header ?? src?.headerName ?? gField,
|
|
5077
|
+
width: def2?.width ?? 160,
|
|
5078
|
+
sortable: false,
|
|
5079
|
+
filterable: false,
|
|
5080
|
+
disableColumnMenu: true,
|
|
5081
|
+
hideable: false,
|
|
5082
|
+
__groupField: gField,
|
|
5083
|
+
__groupIndex: i
|
|
5084
|
+
};
|
|
5085
|
+
});
|
|
5086
|
+
return [...groupCols, ...dataCols];
|
|
5087
|
+
}
|
|
5088
|
+
const def = typeof groupingColDef === "function" ? groupingColDef(activeGroupingModel[0]) : groupingColDef;
|
|
5089
|
+
const singleSrc = resolvedColumns.find((c) => String(c.field) === activeGroupingModel[0] || String(c.key) === activeGroupingModel[0]);
|
|
5090
|
+
const singleGroupCol = {
|
|
5091
|
+
key: "__group__",
|
|
5092
|
+
field: "__group__",
|
|
5093
|
+
header: def?.headerName ?? (activeGroupingModel.length === 1 ? singleSrc?.header ?? singleSrc?.headerName ?? "Group" : "Group"),
|
|
5094
|
+
headerName: def?.headerName ?? (activeGroupingModel.length === 1 ? singleSrc?.header ?? singleSrc?.headerName ?? "Group" : "Group"),
|
|
5095
|
+
width: def?.width ?? 200,
|
|
5096
|
+
sortable: false,
|
|
5097
|
+
filterable: false,
|
|
5098
|
+
disableColumnMenu: true,
|
|
5099
|
+
hideable: false
|
|
5100
|
+
};
|
|
5101
|
+
return [singleGroupCol, ...dataCols];
|
|
5102
|
+
}, [resolvedColumns, isGroupingActive, activeGroupingModel, rowGroupingColumnMode, groupingColDef]);
|
|
4926
5103
|
const getLeftOffset = (col, idx) => {
|
|
4927
5104
|
if (col.pinned !== "left") return void 0;
|
|
4928
5105
|
let offset2 = 0;
|
|
@@ -4957,7 +5134,14 @@ function DataGrid({
|
|
|
4957
5134
|
};
|
|
4958
5135
|
const activeMenuCol = activeMenu ? resolvedColumns.find((c) => String(c.field) === activeMenu) : null;
|
|
4959
5136
|
const alignClass = (align) => align === "center" ? "dg-slot--center" : align === "right" ? "dg-slot--right" : "dg-slot--left";
|
|
4960
|
-
|
|
5137
|
+
const tOpts = toolbarOptions ?? {};
|
|
5138
|
+
const showSearch = !tOpts.hideSearch;
|
|
5139
|
+
const showFilterBtn = !tOpts.hideFilter;
|
|
5140
|
+
const showColumnsBtn = !tOpts.hideColumns;
|
|
5141
|
+
const showExportBtn = !tOpts.hideExport && !hideTopExport;
|
|
5142
|
+
const showTitle = !tOpts.hideTitle;
|
|
5143
|
+
const showRecordCount = !tOpts.hideRecordCount;
|
|
5144
|
+
return /* @__PURE__ */ React75.createElement("div", { className: ["dg-root", sxClass, className].filter(Boolean).join(" ") }, !tOpts.hideHeader && /* @__PURE__ */ React75.createElement("div", { className: `dg-header${customToolbar ? " dg-header--custom" : ""}` }, !customToolbar && (showTitle || showRecordCount) && /* @__PURE__ */ React75.createElement("div", { className: "dg-header-info" }, showTitle && /* @__PURE__ */ React75.createElement("h2", null, title), showRecordCount && /* @__PURE__ */ React75.createElement("p", null, filteredData.length, " total records")), /* @__PURE__ */ React75.createElement("div", { className: "dg-header-actions" }, customToolbar ?? /* @__PURE__ */ React75.createElement(React75.Fragment, null, showSearch && /* @__PURE__ */ React75.createElement("div", { className: "dg-search-wrap" }, /* @__PURE__ */ React75.createElement(Search, { size: 15 }), /* @__PURE__ */ React75.createElement(
|
|
4961
5145
|
"input",
|
|
4962
5146
|
{
|
|
4963
5147
|
className: "dg-search",
|
|
@@ -4968,23 +5152,35 @@ function DataGrid({
|
|
|
4968
5152
|
setCurrentPage(1);
|
|
4969
5153
|
}
|
|
4970
5154
|
}
|
|
4971
|
-
)), /* @__PURE__ */ React75.createElement(Tooltip, { title: "Filters", placement: "top" }, /* @__PURE__ */ React75.createElement(
|
|
5155
|
+
)), showFilterBtn && /* @__PURE__ */ React75.createElement(Tooltip, { title: "Filters", placement: "top" }, /* @__PURE__ */ React75.createElement(
|
|
4972
5156
|
"button",
|
|
4973
5157
|
{
|
|
4974
5158
|
className: `dg-icon-btn ${hasActiveFilters ? "active" : ""}`,
|
|
4975
5159
|
onClick: () => setShowAdvancedFilter(true)
|
|
4976
5160
|
},
|
|
4977
5161
|
/* @__PURE__ */ React75.createElement(Filter, { size: 16 })
|
|
4978
|
-
)), /* @__PURE__ */ React75.createElement(Tooltip, { title: "Manage Columns", placement: "top" }, /* @__PURE__ */ React75.createElement(
|
|
5162
|
+
)), showColumnsBtn && /* @__PURE__ */ React75.createElement(Tooltip, { title: "Manage Columns", placement: "top" }, /* @__PURE__ */ React75.createElement(
|
|
4979
5163
|
"button",
|
|
4980
5164
|
{
|
|
4981
5165
|
className: "dg-icon-btn",
|
|
4982
5166
|
onClick: () => setShowManageColumns(true)
|
|
4983
5167
|
},
|
|
4984
5168
|
/* @__PURE__ */ React75.createElement(Columns, { size: 16 })
|
|
4985
|
-
)),
|
|
5169
|
+
)), showExportBtn && /* @__PURE__ */ React75.createElement("button", { className: "dg-action-btn", onClick: handleExport }, /* @__PURE__ */ React75.createElement(Download, { size: 14 }), " Export CSV")), headerActions && /* @__PURE__ */ React75.createElement("div", { className: `dg-header-slot ${alignClass(headerActions.align)}` }, headerActions.content))), !tOpts.hideHeader && /* @__PURE__ */ React75.createElement("div", { className: `dg-toolbar ${alignClass(toolbarContent?.align)}` }, toolbarContent?.content || ""), isGroupingActive && /* @__PURE__ */ React75.createElement("div", { className: "dg-grouping-bar" }, /* @__PURE__ */ React75.createElement("span", { className: "dg-grouping-bar-label" }, "Grouped by"), activeGroupingModel.map((gField) => {
|
|
5170
|
+
const col = resolvedColumns.find((c) => String(c.field) === gField || String(c.key) === gField);
|
|
5171
|
+
return /* @__PURE__ */ React75.createElement("div", { key: gField, className: "dg-group-chip" }, /* @__PURE__ */ React75.createElement(Layers, { size: 11 }), /* @__PURE__ */ React75.createElement("span", null, col?.header ?? col?.headerName ?? gField), !disableRowGrouping && /* @__PURE__ */ React75.createElement(
|
|
5172
|
+
"button",
|
|
5173
|
+
{
|
|
5174
|
+
className: "dg-group-chip-remove",
|
|
5175
|
+
onClick: () => removeFromGrouping(gField),
|
|
5176
|
+
title: `Remove grouping by ${col?.header ?? gField}`
|
|
5177
|
+
},
|
|
5178
|
+
/* @__PURE__ */ React75.createElement(X2, { size: 10 })
|
|
5179
|
+
));
|
|
5180
|
+
})), /* @__PURE__ */ React75.createElement("div", { className: `dg-table-wrap${filteredData.length === 0 && !loading ? " dg-table-wrap--empty" : ""} ${tOpts.hideHeader ? "rm-top-border" : ""} ${tOpts.hideFooter ? "rm-bottom-border" : ""}` }, loading && /* @__PURE__ */ React75.createElement("div", { className: "dg-loading-overlay" }, /* @__PURE__ */ React75.createElement("div", { className: "dg-loading-spinner" })), /* @__PURE__ */ React75.createElement("table", { className: "dg-table" }, /* @__PURE__ */ React75.createElement("thead", null, /* @__PURE__ */ React75.createElement("tr", null, visibleColumns.map((col, idx) => {
|
|
4986
5181
|
const colField = String(col.field);
|
|
4987
|
-
const
|
|
5182
|
+
const colNativeWidth = col.width ? typeof col.width === "number" ? col.width : parseInt(String(col.width)) : 200;
|
|
5183
|
+
const width = columnWidths[colField] || colNativeWidth;
|
|
4988
5184
|
const leftOffset = getLeftOffset(col, idx);
|
|
4989
5185
|
const rightOffset = getRightOffset(col, idx);
|
|
4990
5186
|
const isSorted = sortField === col.field;
|
|
@@ -5035,79 +5231,150 @@ function DataGrid({
|
|
|
5035
5231
|
}
|
|
5036
5232
|
)))
|
|
5037
5233
|
);
|
|
5038
|
-
}), actions && /* @__PURE__ */ React75.createElement("th", { style: { width: 0, padding: 0 } }))), /* @__PURE__ */ React75.createElement("tbody", null,
|
|
5039
|
-
|
|
5040
|
-
|
|
5041
|
-
|
|
5042
|
-
|
|
5043
|
-
|
|
5044
|
-
|
|
5045
|
-
|
|
5046
|
-
|
|
5047
|
-
|
|
5048
|
-
|
|
5049
|
-
|
|
5050
|
-
|
|
5051
|
-
|
|
5052
|
-
|
|
5053
|
-
|
|
5054
|
-
|
|
5055
|
-
|
|
5056
|
-
|
|
5057
|
-
|
|
5058
|
-
|
|
5059
|
-
|
|
5060
|
-
|
|
5061
|
-
|
|
5062
|
-
|
|
5063
|
-
|
|
5064
|
-
|
|
5065
|
-
|
|
5066
|
-
|
|
5067
|
-
|
|
5068
|
-
|
|
5234
|
+
}), actions && /* @__PURE__ */ React75.createElement("th", { style: { width: 0, padding: 0 } }))), /* @__PURE__ */ React75.createElement("tbody", null, displayRows.length > 0 && displayRows.map((entry) => {
|
|
5235
|
+
if (entry.kind === "group") {
|
|
5236
|
+
const isExpanded = expandedGroups.has(entry.id);
|
|
5237
|
+
const colDef = typeof groupingColDef === "function" ? groupingColDef(entry.field) : groupingColDef;
|
|
5238
|
+
const fieldLabel = resolvedColumns.find(
|
|
5239
|
+
(c) => String(c.field) === entry.field || String(c.key) === entry.field
|
|
5240
|
+
)?.header ?? entry.field;
|
|
5241
|
+
const totalCols = visibleColumns.length + (actions ? 1 : 0);
|
|
5242
|
+
return /* @__PURE__ */ React75.createElement("tr", { key: entry.id, className: "dg-group-row" }, /* @__PURE__ */ React75.createElement("td", { colSpan: totalCols, className: "dg-group-cell" }, /* @__PURE__ */ React75.createElement(
|
|
5243
|
+
"div",
|
|
5244
|
+
{
|
|
5245
|
+
className: "dg-group-cell-inner",
|
|
5246
|
+
style: { paddingLeft: entry.depth * 20 },
|
|
5247
|
+
onClick: () => toggleGroup(entry.id)
|
|
5248
|
+
},
|
|
5249
|
+
/* @__PURE__ */ React75.createElement("button", { className: "dg-group-toggle", onClick: (e) => {
|
|
5250
|
+
e.stopPropagation();
|
|
5251
|
+
toggleGroup(entry.id);
|
|
5252
|
+
} }, isExpanded ? /* @__PURE__ */ React75.createElement(ChevronDown, { size: 15 }) : /* @__PURE__ */ React75.createElement(ChevronRight, { size: 15 })),
|
|
5253
|
+
activeGroupingModel.length > 1 && /* @__PURE__ */ React75.createElement("span", { className: "dg-group-field-label" }, fieldLabel, ":"),
|
|
5254
|
+
colDef?.renderCell ? colDef.renderCell({ groupKey: entry.key, field: entry.field, depth: entry.depth, leafCount: entry.leafCount }) : /* @__PURE__ */ React75.createElement("span", { className: "dg-group-key" }, entry.key),
|
|
5255
|
+
!colDef?.hideDescendantCount && /* @__PURE__ */ React75.createElement("span", { className: "dg-group-count" }, entry.leafCount)
|
|
5256
|
+
)));
|
|
5257
|
+
}
|
|
5258
|
+
const item = entry.row;
|
|
5259
|
+
const rowDepth = entry.depth;
|
|
5260
|
+
return /* @__PURE__ */ React75.createElement("tr", { key: item.id, className: "dg-tbody-row", onDoubleClick: () => onRowDoubleClick?.(item) }, visibleColumns.map((col, idx) => {
|
|
5261
|
+
const colField = String(col.field);
|
|
5262
|
+
if (colField === "__tree__") {
|
|
5263
|
+
const treeColWidth = columnWidths["__tree__"] || 44;
|
|
5264
|
+
const isExpanded = treeExpandedRows.has(item.id);
|
|
5265
|
+
return /* @__PURE__ */ React75.createElement(
|
|
5266
|
+
"td",
|
|
5267
|
+
{
|
|
5268
|
+
key: `${item.id}-__tree__`,
|
|
5269
|
+
className: "dg-tree-cell",
|
|
5270
|
+
style: { width: treeColWidth, minWidth: treeColWidth, maxWidth: treeColWidth }
|
|
5271
|
+
},
|
|
5272
|
+
/* @__PURE__ */ React75.createElement("div", { className: "dg-tree-cell-inner", style: { paddingLeft: rowDepth * 20 } }, entry.hasChildren ? /* @__PURE__ */ React75.createElement(
|
|
5273
|
+
"button",
|
|
5069
5274
|
{
|
|
5070
|
-
className: "dg-
|
|
5071
|
-
|
|
5072
|
-
|
|
5073
|
-
|
|
5074
|
-
onClick: (e) => e.stopPropagation(),
|
|
5075
|
-
onKeyDown: (e) => {
|
|
5076
|
-
if (e.key === "Enter") commit(e.target.value);
|
|
5077
|
-
if (e.key === "Escape") setEditingCell(null);
|
|
5078
|
-
},
|
|
5079
|
-
onBlur: (e) => {
|
|
5080
|
-
const finalValue = e.target.value;
|
|
5081
|
-
setEditingCell(null);
|
|
5082
|
-
col.onBlur?.({ value: finalValue, row: item, field });
|
|
5275
|
+
className: "dg-group-toggle",
|
|
5276
|
+
onClick: (e) => {
|
|
5277
|
+
e.stopPropagation();
|
|
5278
|
+
toggleTreeRow(item.id);
|
|
5083
5279
|
}
|
|
5084
|
-
}
|
|
5085
|
-
|
|
5086
|
-
|
|
5087
|
-
|
|
5088
|
-
|
|
5089
|
-
|
|
5090
|
-
|
|
5091
|
-
|
|
5092
|
-
|
|
5280
|
+
},
|
|
5281
|
+
isExpanded ? /* @__PURE__ */ React75.createElement(ChevronDown, { size: 15 }) : /* @__PURE__ */ React75.createElement(ChevronRight, { size: 15 })
|
|
5282
|
+
) : /* @__PURE__ */ React75.createElement("span", { style: { display: "inline-block", width: 22 } }))
|
|
5283
|
+
);
|
|
5284
|
+
}
|
|
5285
|
+
if (colField === "__group__" || colField.startsWith("__group_")) {
|
|
5286
|
+
const colDef = typeof groupingColDef === "function" ? groupingColDef(colField) : groupingColDef;
|
|
5287
|
+
const leafField = colDef?.leafField;
|
|
5288
|
+
let leafContent = null;
|
|
5289
|
+
if (leafField) {
|
|
5290
|
+
const leafCol = resolvedColumns.find((c) => String(c.field) === leafField || String(c.key) === leafField);
|
|
5291
|
+
if (leafCol) {
|
|
5292
|
+
const raw = item[String(leafCol.field)];
|
|
5293
|
+
let val = leafCol.valueGetter ? leafCol.valueGetter({ value: raw, row: item, field: leafField }) : raw;
|
|
5294
|
+
if (leafCol.valueFormatter) val = leafCol.valueFormatter({ value: val, row: item, field: leafField });
|
|
5295
|
+
if (leafCol.renderCell) leafContent = leafCol.renderCell({ value: val, row: item, field: leafField });
|
|
5296
|
+
else leafContent = val == null ? "" : String(val);
|
|
5297
|
+
}
|
|
5093
5298
|
}
|
|
5094
|
-
|
|
5095
|
-
|
|
5096
|
-
|
|
5097
|
-
|
|
5098
|
-
|
|
5099
|
-
|
|
5100
|
-
|
|
5101
|
-
|
|
5102
|
-
|
|
5103
|
-
|
|
5104
|
-
|
|
5105
|
-
|
|
5106
|
-
|
|
5107
|
-
|
|
5108
|
-
|
|
5109
|
-
|
|
5110
|
-
|
|
5299
|
+
const groupColWidth = columnWidths[colField] || 200;
|
|
5300
|
+
return /* @__PURE__ */ React75.createElement(
|
|
5301
|
+
"td",
|
|
5302
|
+
{
|
|
5303
|
+
key: `${item.id}-${colField}`,
|
|
5304
|
+
className: "dg-group-leaf-cell",
|
|
5305
|
+
style: { width: groupColWidth, minWidth: groupColWidth, maxWidth: groupColWidth, paddingLeft: rowDepth * 20 + 32 }
|
|
5306
|
+
},
|
|
5307
|
+
leafContent
|
|
5308
|
+
);
|
|
5309
|
+
}
|
|
5310
|
+
const width = columnWidths[colField] || 200;
|
|
5311
|
+
const leftOffset = getLeftOffset(col, idx);
|
|
5312
|
+
const rightOffset = getRightOffset(col, idx);
|
|
5313
|
+
return /* @__PURE__ */ React75.createElement(
|
|
5314
|
+
"td",
|
|
5315
|
+
{
|
|
5316
|
+
key: `${item.id}-${colField}`,
|
|
5317
|
+
className: `dg-td${col.pinned === "left" ? " pinned-left" : col.pinned === "right" ? " pinned-right" : ""}${col.editable ? " dg-td--editable" : ""} ${col.cellClassName || ""}`,
|
|
5318
|
+
style: { width, minWidth: width, maxWidth: width, left: leftOffset, right: rightOffset, flex: col.flex },
|
|
5319
|
+
onDoubleClick: () => onCellDoubleClick?.({ row: item, field: colField, value: item[col.field || ""] }),
|
|
5320
|
+
onClick: col.editable ? () => {
|
|
5321
|
+
const field = String(col.field);
|
|
5322
|
+
const rawValue = item[col.field || ""];
|
|
5323
|
+
const value = col.valueGetter ? col.valueGetter({ value: rawValue, row: item, field }) : rawValue;
|
|
5324
|
+
setEditingCell({ rowId: item.id, field, value });
|
|
5325
|
+
} : void 0
|
|
5326
|
+
},
|
|
5327
|
+
(() => {
|
|
5328
|
+
const field = String(col.field);
|
|
5329
|
+
const rawValue = item[col.field || ""];
|
|
5330
|
+
let value = col.valueGetter ? col.valueGetter({ value: rawValue, row: item, field }) : rawValue;
|
|
5331
|
+
if (col.editable && editingCell?.rowId === item.id && editingCell?.field === field) {
|
|
5332
|
+
const inputType = col.type === "number" ? "number" : col.type === "date" ? "date" : "text";
|
|
5333
|
+
const commit = (finalValue) => {
|
|
5334
|
+
setEditingCell(null);
|
|
5335
|
+
col.onEnter?.({ value: finalValue, row: item, field });
|
|
5336
|
+
};
|
|
5337
|
+
return /* @__PURE__ */ React75.createElement(
|
|
5338
|
+
"input",
|
|
5339
|
+
{
|
|
5340
|
+
className: "dg-cell-editor",
|
|
5341
|
+
type: inputType,
|
|
5342
|
+
autoFocus: true,
|
|
5343
|
+
defaultValue: editingCell.value ?? "",
|
|
5344
|
+
onClick: (e) => e.stopPropagation(),
|
|
5345
|
+
onKeyDown: (e) => {
|
|
5346
|
+
if (e.key === "Enter") commit(e.target.value);
|
|
5347
|
+
if (e.key === "Escape") setEditingCell(null);
|
|
5348
|
+
},
|
|
5349
|
+
onBlur: (e) => {
|
|
5350
|
+
const finalValue = e.target.value;
|
|
5351
|
+
setEditingCell(null);
|
|
5352
|
+
col.onBlur?.({ value: finalValue, row: item, field });
|
|
5353
|
+
}
|
|
5354
|
+
}
|
|
5355
|
+
);
|
|
5356
|
+
}
|
|
5357
|
+
const formattedValue = col.valueFormatter ? col.valueFormatter({ value, row: item, field }) : value;
|
|
5358
|
+
if (col.renderCell) return col.renderCell({ value, row: item, field });
|
|
5359
|
+
if (col.render) return col.render(value, item);
|
|
5360
|
+
return String(formattedValue ?? "");
|
|
5361
|
+
})()
|
|
5362
|
+
);
|
|
5363
|
+
}), actions && /* @__PURE__ */ React75.createElement("td", { className: "dg-row-actions-cell" }, (() => {
|
|
5364
|
+
const resolvedActions = typeof actions === "function" ? actions(item) : actions;
|
|
5365
|
+
const visibleActions = resolvedActions.filter((a) => !a.show || a.show(item));
|
|
5366
|
+
if (visibleActions.length === 0) return null;
|
|
5367
|
+
return /* @__PURE__ */ React75.createElement("div", { className: "dg-row-actions" }, /* @__PURE__ */ React75.createElement("div", { className: "dg-action-group" }, visibleActions.map((action, i) => /* @__PURE__ */ React75.createElement(Tooltip, { key: i, title: action.label, placement: "top" }, /* @__PURE__ */ React75.createElement(
|
|
5368
|
+
"button",
|
|
5369
|
+
{
|
|
5370
|
+
className: "dg-row-action-btn",
|
|
5371
|
+
style: { color: action.color || "var(--text-secondary)" },
|
|
5372
|
+
onClick: () => action.onClick(item)
|
|
5373
|
+
},
|
|
5374
|
+
action.icon
|
|
5375
|
+
)))));
|
|
5376
|
+
})()));
|
|
5377
|
+
}))), filteredData.length === 0 && /* @__PURE__ */ React75.createElement("div", { className: "dg-empty-state" }, /* @__PURE__ */ React75.createElement("svg", { className: "dg-empty-icon", viewBox: "0 0 200 160", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, /* @__PURE__ */ React75.createElement("rect", { x: "20", y: "30", width: "160", height: "100", rx: "8", fill: "var(--hover-color)", stroke: "var(--border-color)", strokeWidth: "1.5" }), /* @__PURE__ */ React75.createElement("rect", { x: "20", y: "30", width: "160", height: "28", rx: "8", fill: "var(--border-color)", opacity: "0.5" }), /* @__PURE__ */ React75.createElement("rect", { x: "20", y: "50", width: "160", height: "8", rx: "0", fill: "var(--border-color)", opacity: "0.5" }), /* @__PURE__ */ React75.createElement("line", { x1: "72", y1: "30", x2: "72", y2: "130", stroke: "var(--border-color)", strokeWidth: "1" }), /* @__PURE__ */ React75.createElement("line", { x1: "128", y1: "30", x2: "128", y2: "130", stroke: "var(--border-color)", strokeWidth: "1" }), /* @__PURE__ */ React75.createElement("line", { x1: "20", y1: "78", x2: "180", y2: "78", stroke: "var(--border-color)", strokeWidth: "1" }), /* @__PURE__ */ React75.createElement("line", { x1: "20", y1: "104", x2: "180", y2: "104", stroke: "var(--border-color)", strokeWidth: "1" }), /* @__PURE__ */ React75.createElement("rect", { x: "32", y: "87", width: "28", height: "6", rx: "3", fill: "var(--border-color)", opacity: "0.4" }), /* @__PURE__ */ React75.createElement("rect", { x: "84", y: "87", width: "28", height: "6", rx: "3", fill: "var(--border-color)", opacity: "0.4" }), /* @__PURE__ */ React75.createElement("rect", { x: "140", y: "87", width: "28", height: "6", rx: "3", fill: "var(--border-color)", opacity: "0.4" }), /* @__PURE__ */ React75.createElement("rect", { x: "32", y: "113", width: "20", height: "6", rx: "3", fill: "var(--border-color)", opacity: "0.3" }), /* @__PURE__ */ React75.createElement("rect", { x: "84", y: "113", width: "32", height: "6", rx: "3", fill: "var(--border-color)", opacity: "0.3" }), /* @__PURE__ */ React75.createElement("rect", { x: "140", y: "113", width: "20", height: "6", rx: "3", fill: "var(--border-color)", opacity: "0.3" }), /* @__PURE__ */ React75.createElement("circle", { cx: "148", cy: "108", r: "26", fill: "var(--surface-color)", stroke: "var(--border-color)", strokeWidth: "1.5" }), /* @__PURE__ */ React75.createElement("circle", { cx: "145", cy: "105", r: "10", stroke: "var(--text-secondary)", strokeWidth: "2.5", opacity: "0.5" }), /* @__PURE__ */ React75.createElement("line", { x1: "152", y1: "113", x2: "161", y2: "122", stroke: "var(--text-secondary)", strokeWidth: "2.5", strokeLinecap: "round", opacity: "0.5" }), /* @__PURE__ */ React75.createElement("line", { x1: "141", y1: "101", x2: "149", y2: "109", stroke: "var(--text-secondary)", strokeWidth: "2", strokeLinecap: "round", opacity: "0.5" }), /* @__PURE__ */ React75.createElement("line", { x1: "149", y1: "101", x2: "141", y2: "109", stroke: "var(--text-secondary)", strokeWidth: "2", strokeLinecap: "round", opacity: "0.5" })), /* @__PURE__ */ React75.createElement("p", { className: "dg-empty-title" }, "No data found"), /* @__PURE__ */ React75.createElement("p", { className: "dg-empty-subtitle" }, filterText || hasActiveFilters ? "Try adjusting your search or filters" : "No records to display"))), customFooter ? /* @__PURE__ */ React75.createElement("div", { className: "dg-pagination dg-pagination--custom" }, customFooter) : pagination && !tOpts.hideFooter && /* @__PURE__ */ React75.createElement("div", { className: "dg-pagination" }, /* @__PURE__ */ React75.createElement("div", { className: "dg-page-info" }, /* @__PURE__ */ React75.createElement(Tooltip, { title: "Export CSV", placement: "top" }, /* @__PURE__ */ React75.createElement("button", { className: "dg-icon-btn", onClick: handleExport }, /* @__PURE__ */ React75.createElement(Download, { size: 14 }))), /* @__PURE__ */ React75.createElement("div", { className: "dg-per-page" }, /* @__PURE__ */ React75.createElement("span", null, "Rows per page:"), /* @__PURE__ */ React75.createElement(
|
|
5111
5378
|
FilterSelect,
|
|
5112
5379
|
{
|
|
5113
5380
|
placement: "top",
|
|
@@ -5148,6 +5415,17 @@ function DataGrid({
|
|
|
5148
5415
|
setShowAdvancedFilter(true);
|
|
5149
5416
|
setActiveMenu(null);
|
|
5150
5417
|
} }, /* @__PURE__ */ React75.createElement(Filter, { size: 14 }), " Filter\u2026"),
|
|
5418
|
+
!disableRowGrouping && activeMenuCol?.groupable !== false && (() => {
|
|
5419
|
+
const gField = String(activeMenuCol?.field ?? "");
|
|
5420
|
+
const isGrouped = activeGroupingModel.includes(gField);
|
|
5421
|
+
return isGrouped ? /* @__PURE__ */ React75.createElement("button", { className: "dg-menu-item", onClick: () => {
|
|
5422
|
+
removeFromGrouping(gField);
|
|
5423
|
+
setActiveMenu(null);
|
|
5424
|
+
} }, /* @__PURE__ */ React75.createElement(Layers, { size: 14 }), " Ungroup") : /* @__PURE__ */ React75.createElement("button", { className: "dg-menu-item", onClick: () => {
|
|
5425
|
+
addToGrouping(gField);
|
|
5426
|
+
setActiveMenu(null);
|
|
5427
|
+
} }, /* @__PURE__ */ React75.createElement(Layers, { size: 14 }), " Group by");
|
|
5428
|
+
})(),
|
|
5151
5429
|
/* @__PURE__ */ React75.createElement("button", { className: "dg-menu-item", onClick: () => toggleHide(activeMenu) }, /* @__PURE__ */ React75.createElement(EyeOff, { size: 14 }), " Hide column"),
|
|
5152
5430
|
/* @__PURE__ */ React75.createElement("button", { className: "dg-menu-item", onClick: () => {
|
|
5153
5431
|
setShowManageColumns(true);
|