@vesture/react 0.2.7 → 0.2.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.js CHANGED
@@ -1116,12 +1116,18 @@ var body3 = "DataGrid_body__7xivx77";
1116
1116
  var cell = "DataGrid_cell__7xivx79";
1117
1117
  var checkboxCell = "DataGrid_checkboxCell__7xivx7a";
1118
1118
  var container = "DataGrid_container__7xivx71";
1119
- var editInput = "DataGrid_editInput__7xivx7p";
1119
+ var editInput = "DataGrid_editInput__7xivx7v";
1120
1120
  var emptyState = "DataGrid_emptyState__7xivx7b";
1121
1121
  var filterCell = "DataGrid_filterCell__7xivx7j";
1122
1122
  var filterInput = "DataGrid_filterInput__7xivx7k";
1123
1123
  var filterRow = "DataGrid_filterRow__7xivx7i";
1124
1124
  var gridWrapper = "DataGrid_gridWrapper__7xivx7m";
1125
+ var groupAggregateItem = "DataGrid_groupAggregateItem__7xivx7u";
1126
+ var groupAggregates = "DataGrid_groupAggregates__7xivx7t";
1127
+ var groupChevron = "DataGrid_groupChevron__7xivx7q";
1128
+ var groupCount = "DataGrid_groupCount__7xivx7s";
1129
+ var groupLabel = "DataGrid_groupLabel__7xivx7r";
1130
+ var groupRow = "DataGrid_groupRow__7xivx7p";
1125
1131
  var headerButton = "DataGrid_headerButton__7xivx74";
1126
1132
  var headerCell = "DataGrid_headerCell__7xivx73";
1127
1133
  var headerRow = "DataGrid_headerRow__7xivx72";
@@ -1206,6 +1212,40 @@ function getCellValue(column, row3) {
1206
1212
  }
1207
1213
  return row3[column.key];
1208
1214
  }
1215
+ function getGroupValue(row3, groupBy, column) {
1216
+ if (column) {
1217
+ return String(getCellValue(column, row3) ?? "");
1218
+ }
1219
+ return String(row3[groupBy] ?? "");
1220
+ }
1221
+ function formatAggregateNumber(value) {
1222
+ return Number.isInteger(value) ? value : value.toFixed(2);
1223
+ }
1224
+ function computeAggregate(column, rows) {
1225
+ const { aggregate } = column;
1226
+ if (!aggregate) return null;
1227
+ if (typeof aggregate === "function") {
1228
+ return aggregate(rows);
1229
+ }
1230
+ if (aggregate === "count") {
1231
+ return rows.length;
1232
+ }
1233
+ const values = rows.map((r) => Number(getCellValue(column, r)) || 0);
1234
+ switch (aggregate) {
1235
+ case "sum":
1236
+ return formatAggregateNumber(values.reduce((a, b) => a + b, 0));
1237
+ case "avg":
1238
+ return formatAggregateNumber(
1239
+ values.length ? values.reduce((a, b) => a + b, 0) / values.length : 0
1240
+ );
1241
+ case "min":
1242
+ return formatAggregateNumber(values.length ? Math.min(...values) : 0);
1243
+ case "max":
1244
+ return formatAggregateNumber(values.length ? Math.max(...values) : 0);
1245
+ default:
1246
+ return null;
1247
+ }
1248
+ }
1209
1249
  function DataGridInner({
1210
1250
  columns,
1211
1251
  data,
@@ -1229,6 +1269,13 @@ function DataGridInner({
1229
1269
  pageSize,
1230
1270
  onPageChange,
1231
1271
  enableExport = false,
1272
+ groupBy: controlledGroupBy,
1273
+ defaultGroupBy,
1274
+ onGroupByChange,
1275
+ expandedGroups: controlledExpandedGroups,
1276
+ defaultExpandedGroups,
1277
+ onExpandedGroupsChange,
1278
+ groupRowHeight,
1232
1279
  onRowClick,
1233
1280
  onRowDoubleClick,
1234
1281
  onCellClick
@@ -1248,10 +1295,31 @@ function DataGridInner({
1248
1295
  const [scrollTop, setScrollTop] = useState8(0);
1249
1296
  const [editingRowId, setEditingRowId] = useState8(null);
1250
1297
  const [editDraft, setEditDraft] = useState8({});
1298
+ const [uncontrolledGroupBy, setUncontrolledGroupBy] = useState8(defaultGroupBy);
1299
+ const [uncontrolledExpandedGroups, setUncontrolledExpandedGroups] = useState8(defaultExpandedGroups);
1251
1300
  const editingEnabled = Boolean(onRowEdit);
1252
1301
  const sort = controlledSort !== void 0 ? controlledSort : uncontrolledSort;
1253
1302
  const filters = controlledFilters !== void 0 ? controlledFilters : uncontrolledFilters;
1254
1303
  const selectedIds = controlledSelectedIds ?? uncontrolledSelectedIds;
1304
+ const groupBy = controlledGroupBy !== void 0 ? controlledGroupBy : uncontrolledGroupBy;
1305
+ const expandedGroups = controlledExpandedGroups !== void 0 ? controlledExpandedGroups : uncontrolledExpandedGroups;
1306
+ const setExpandedGroups = (next) => {
1307
+ if (controlledExpandedGroups === void 0) {
1308
+ setUncontrolledExpandedGroups(next);
1309
+ }
1310
+ onExpandedGroupsChange?.(next);
1311
+ };
1312
+ const isGroupExpanded = (key) => expandedGroups === void 0 ? true : expandedGroups.has(key);
1313
+ const toggleGroupExpanded = (key, allGroupKeys) => {
1314
+ const current2 = expandedGroups ?? new Set(allGroupKeys);
1315
+ const next = new Set(current2);
1316
+ if (next.has(key)) {
1317
+ next.delete(key);
1318
+ } else {
1319
+ next.add(key);
1320
+ }
1321
+ setExpandedGroups(next);
1322
+ };
1255
1323
  const setSort = (next) => {
1256
1324
  if (controlledSort === void 0) {
1257
1325
  setUncontrolledSort(next);
@@ -1315,6 +1383,44 @@ function DataGridInner({
1315
1383
  );
1316
1384
  return sort.direction === "desc" ? sorted.reverse() : sorted;
1317
1385
  }, [filteredData, sort, columns, serverSide, data]);
1386
+ const groupColumn = useMemo2(
1387
+ () => groupBy ? columns.find((c) => c.key === groupBy) : void 0,
1388
+ [columns, groupBy]
1389
+ );
1390
+ const groupedMap = useMemo2(() => {
1391
+ if (!groupBy) return null;
1392
+ const map = /* @__PURE__ */ new Map();
1393
+ for (const row3 of sortedData) {
1394
+ const key = getGroupValue(row3, groupBy, groupColumn);
1395
+ const existing = map.get(key);
1396
+ if (existing) {
1397
+ existing.push(row3);
1398
+ } else {
1399
+ map.set(key, [row3]);
1400
+ }
1401
+ }
1402
+ return map;
1403
+ }, [sortedData, groupBy, groupColumn]);
1404
+ const flatEntries = useMemo2(() => {
1405
+ if (!groupedMap) {
1406
+ return sortedData.map((row3) => ({ type: "data", row: row3 }));
1407
+ }
1408
+ const entries = [];
1409
+ for (const [key, rows] of groupedMap) {
1410
+ const collapsed = !isGroupExpanded(key);
1411
+ entries.push({ type: "group", key, rows, collapsed });
1412
+ if (!collapsed) {
1413
+ for (const row3 of rows) {
1414
+ entries.push({ type: "data", row: row3 });
1415
+ }
1416
+ }
1417
+ }
1418
+ return entries;
1419
+ }, [groupedMap, expandedGroups, sortedData]);
1420
+ const visibleDataRows = useMemo2(
1421
+ () => flatEntries.filter((e) => e.type === "data").map((e) => e.row),
1422
+ [flatEntries]
1423
+ );
1318
1424
  const exportToExcel = useCallback2(
1319
1425
  async (options) => {
1320
1426
  const XLSX = await import("xlsx");
@@ -1348,13 +1454,13 @@ function DataGridInner({
1348
1454
  }, [columns, data]);
1349
1455
  const hasFilterableColumns = columns.some((c) => c.filterable);
1350
1456
  const showPagination = page !== void 0 && pageSize !== void 0 && onPageChange !== void 0;
1351
- const allSelected = sortedData.length > 0 && sortedData.every((r) => selectedIds.has(getRowId(r)));
1352
- const someSelected = !allSelected && sortedData.some((r) => selectedIds.has(getRowId(r)));
1457
+ const allSelected = visibleDataRows.length > 0 && visibleDataRows.every((r) => selectedIds.has(getRowId(r)));
1458
+ const someSelected = !allSelected && visibleDataRows.some((r) => selectedIds.has(getRowId(r)));
1353
1459
  const toggleAll = () => {
1354
1460
  if (allSelected) {
1355
1461
  setSelectedIds(/* @__PURE__ */ new Set());
1356
1462
  } else {
1357
- setSelectedIds(new Set(sortedData.map(getRowId)));
1463
+ setSelectedIds(new Set(visibleDataRows.map(getRowId)));
1358
1464
  }
1359
1465
  };
1360
1466
  const toggleRow = (id) => {
@@ -1479,11 +1585,47 @@ function DataGridInner({
1479
1585
  setEditingRowId(null);
1480
1586
  setEditDraft({});
1481
1587
  };
1482
- const totalHeight = sortedData.length * rowHeight;
1483
- const visibleCount = Math.ceil(height / rowHeight) + overscan * 2;
1484
- const startIndex = Math.max(0, Math.floor(scrollTop / rowHeight) - overscan);
1485
- const endIndex = Math.min(sortedData.length, startIndex + visibleCount);
1486
- const visibleRows = sortedData.slice(startIndex, endIndex);
1588
+ const resolvedGroupRowHeight = groupRowHeight ?? rowHeight;
1589
+ const rowOffsets = groupedMap ? (() => {
1590
+ const offsets = new Array(flatEntries.length);
1591
+ let acc = 0;
1592
+ for (let i = 0; i < flatEntries.length; i++) {
1593
+ offsets[i] = acc;
1594
+ acc += flatEntries[i].type === "group" ? resolvedGroupRowHeight : rowHeight;
1595
+ }
1596
+ return offsets;
1597
+ })() : null;
1598
+ function findIndexAtOffset(offsets, target) {
1599
+ let lo = 0;
1600
+ let hi = offsets.length - 1;
1601
+ let ans = 0;
1602
+ while (lo <= hi) {
1603
+ const mid = lo + hi >> 1;
1604
+ if (offsets[mid] <= target) {
1605
+ ans = mid;
1606
+ lo = mid + 1;
1607
+ } else {
1608
+ hi = mid - 1;
1609
+ }
1610
+ }
1611
+ return ans;
1612
+ }
1613
+ let totalHeight;
1614
+ let startIndex;
1615
+ let endIndex;
1616
+ if (rowOffsets) {
1617
+ totalHeight = rowOffsets.length ? rowOffsets[rowOffsets.length - 1] + (flatEntries[flatEntries.length - 1].type === "group" ? resolvedGroupRowHeight : rowHeight) : 0;
1618
+ const rawStart = rowOffsets.length ? findIndexAtOffset(rowOffsets, scrollTop) : 0;
1619
+ startIndex = Math.max(0, rawStart - overscan);
1620
+ const rawEnd = rowOffsets.length ? findIndexAtOffset(rowOffsets, scrollTop + height) + 1 : 0;
1621
+ endIndex = Math.min(flatEntries.length, rawEnd + overscan);
1622
+ } else {
1623
+ totalHeight = sortedData.length * rowHeight;
1624
+ const visibleCount = Math.ceil(height / rowHeight) + overscan * 2;
1625
+ startIndex = Math.max(0, Math.floor(scrollTop / rowHeight) - overscan);
1626
+ endIndex = Math.min(flatEntries.length, startIndex + visibleCount);
1627
+ }
1628
+ const visibleEntries = flatEntries.slice(startIndex, endIndex);
1487
1629
  const totalWidth = (selectable ? CHECKBOX_COLUMN_WIDTH : 0) + (editingEnabled ? ACTIONS_COLUMN_WIDTH : 0) + columns.reduce((sum, c) => sum + widthOf(c), 0);
1488
1630
  return /* @__PURE__ */ jsxs17(Fragment5, { children: [
1489
1631
  /* @__PURE__ */ jsxs17("div", { className: gridWrapper, children: [
@@ -1657,13 +1799,64 @@ function DataGridInner({
1657
1799
  width: totalWidth,
1658
1800
  minWidth: "100%"
1659
1801
  },
1660
- children: visibleRows.map((rowData, i) => {
1802
+ children: visibleEntries.map((entry, i) => {
1661
1803
  const index = startIndex + i;
1804
+ const top = rowOffsets ? rowOffsets[index] : index * rowHeight;
1805
+ if (entry.type === "group") {
1806
+ const isExpanded = !entry.collapsed;
1807
+ const groupLabelText = groupColumn ? typeof groupColumn.header === "string" ? groupColumn.header : groupColumn.key : groupBy;
1808
+ const aggregateColumns = columns.filter((c) => c.aggregate);
1809
+ return /* @__PURE__ */ jsxs17(
1810
+ "div",
1811
+ {
1812
+ className: groupRow,
1813
+ style: {
1814
+ top,
1815
+ height: resolvedGroupRowHeight,
1816
+ width: totalWidth
1817
+ },
1818
+ role: "row",
1819
+ children: [
1820
+ /* @__PURE__ */ jsx34(
1821
+ "button",
1822
+ {
1823
+ type: "button",
1824
+ className: groupChevron,
1825
+ "data-expanded": isExpanded || void 0,
1826
+ onClick: () => toggleGroupExpanded(
1827
+ entry.key,
1828
+ Array.from(groupedMap.keys())
1829
+ ),
1830
+ "aria-label": isExpanded ? `Collapse group ${entry.key}` : `Expand group ${entry.key}`,
1831
+ children: "\u203A"
1832
+ }
1833
+ ),
1834
+ /* @__PURE__ */ jsxs17("span", { className: groupLabel, children: [
1835
+ groupLabelText,
1836
+ ": ",
1837
+ entry.key
1838
+ ] }),
1839
+ /* @__PURE__ */ jsxs17("span", { className: groupCount, children: [
1840
+ entry.rows.length,
1841
+ " row",
1842
+ entry.rows.length === 1 ? "" : "s"
1843
+ ] }),
1844
+ aggregateColumns.length > 0 ? /* @__PURE__ */ jsx34("span", { className: groupAggregates, children: aggregateColumns.map((c) => /* @__PURE__ */ jsxs17("span", { className: groupAggregateItem, children: [
1845
+ typeof c.header === "string" ? c.header : c.key,
1846
+ ": ",
1847
+ computeAggregate(c, entry.rows)
1848
+ ] }, c.key)) }) : null
1849
+ ]
1850
+ },
1851
+ `group-${entry.key}`
1852
+ );
1853
+ }
1854
+ const rowData = entry.row;
1662
1855
  const id = getRowId(rowData);
1663
1856
  const isSelected = selectedIds.has(id);
1664
1857
  const isEditing = editingRowId === id;
1665
1858
  const style = {
1666
- top: index * rowHeight,
1859
+ top,
1667
1860
  height: rowHeight,
1668
1861
  width: totalWidth
1669
1862
  };