bolt-table 0.1.12 → 0.1.14
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/README.md +228 -2
- package/dist/index.d.mts +120 -2
- package/dist/index.d.ts +120 -2
- package/dist/index.js +567 -20
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +567 -20
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -110,6 +110,10 @@ var PinOffIcon = ({ style, className }) => /* @__PURE__ */ (0, import_jsx_runtim
|
|
|
110
110
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "12", x2: "12", y1: "17", y2: "22" }),
|
|
111
111
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M9 9v1.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V17h14v-1.76a2 2 0 0 0-1.11-1.79l-1.78-.9A2 2 0 0 1 15 10.76V6h1a2 2 0 0 0 0-4H8a2 2 0 0 0 0 4" })
|
|
112
112
|
] });
|
|
113
|
+
var CopyIcon = ({ style, className }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { ...svgBase, style, className, children: [
|
|
114
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { width: "14", height: "14", x: "8", y: "8", rx: "2", ry: "2" }),
|
|
115
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" })
|
|
116
|
+
] });
|
|
113
117
|
var EyeOffIcon = ({ style, className }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { ...svgBase, style, className, children: [
|
|
114
118
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M9.88 9.88a3 3 0 1 0 4.24 4.24" }),
|
|
115
119
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M10.73 5.08A10.43 10.43 0 0 1 12 5c7 0 10 7 10 7a13.16 13.16 0 0 1-1.67 2.68" }),
|
|
@@ -165,21 +169,49 @@ var DraggableHeader = import_react.default.memo(
|
|
|
165
169
|
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
166
170
|
}
|
|
167
171
|
}, [contextMenu]);
|
|
168
|
-
const
|
|
169
|
-
e.preventDefault();
|
|
170
|
-
e.stopPropagation();
|
|
172
|
+
const showContextMenuAt = (clientX, clientY) => {
|
|
171
173
|
const menuWidth = 160;
|
|
172
174
|
const menuHeight = 180;
|
|
173
|
-
let x =
|
|
174
|
-
let y =
|
|
175
|
-
if (x + menuWidth > window.innerWidth)
|
|
175
|
+
let x = clientX;
|
|
176
|
+
let y = clientY;
|
|
177
|
+
if (x + menuWidth > window.innerWidth)
|
|
176
178
|
x = window.innerWidth - menuWidth - 10;
|
|
177
|
-
|
|
178
|
-
if (y + menuHeight > window.innerHeight) {
|
|
179
|
+
if (y + menuHeight > window.innerHeight)
|
|
179
180
|
y = window.innerHeight - menuHeight - 10;
|
|
180
|
-
}
|
|
181
181
|
setContextMenu({ x, y });
|
|
182
182
|
};
|
|
183
|
+
const handleContextMenu = (e) => {
|
|
184
|
+
e.preventDefault();
|
|
185
|
+
e.stopPropagation();
|
|
186
|
+
showContextMenuAt(e.clientX, e.clientY);
|
|
187
|
+
};
|
|
188
|
+
const longPressTimerRef = (0, import_react.useRef)(
|
|
189
|
+
null
|
|
190
|
+
);
|
|
191
|
+
const touchStartRef = (0, import_react.useRef)(null);
|
|
192
|
+
const cancelLongPress = () => {
|
|
193
|
+
if (longPressTimerRef.current) {
|
|
194
|
+
clearTimeout(longPressTimerRef.current);
|
|
195
|
+
longPressTimerRef.current = null;
|
|
196
|
+
}
|
|
197
|
+
touchStartRef.current = null;
|
|
198
|
+
};
|
|
199
|
+
const handleTouchStart = (e) => {
|
|
200
|
+
cancelLongPress();
|
|
201
|
+
const touch = e.touches[0];
|
|
202
|
+
touchStartRef.current = { x: touch.clientX, y: touch.clientY };
|
|
203
|
+
longPressTimerRef.current = setTimeout(() => {
|
|
204
|
+
longPressTimerRef.current = null;
|
|
205
|
+
showContextMenuAt(touch.clientX, touch.clientY);
|
|
206
|
+
}, 500);
|
|
207
|
+
};
|
|
208
|
+
const handleTouchMove = (e) => {
|
|
209
|
+
if (!touchStartRef.current) return;
|
|
210
|
+
const touch = e.touches[0];
|
|
211
|
+
const dx = touch.clientX - touchStartRef.current.x;
|
|
212
|
+
const dy = touch.clientY - touchStartRef.current.y;
|
|
213
|
+
if (Math.abs(dx) > 10 || Math.abs(dy) > 10) cancelLongPress();
|
|
214
|
+
};
|
|
183
215
|
const handleResizeStart = (e) => {
|
|
184
216
|
e.preventDefault();
|
|
185
217
|
e.stopPropagation();
|
|
@@ -229,6 +261,10 @@ var DraggableHeader = import_react.default.memo(
|
|
|
229
261
|
style: headerStyle,
|
|
230
262
|
className: `${column.className ?? ""} ${classNames?.header ?? ""} ${isPinned ? classNames?.pinnedHeader ?? "" : ""}`,
|
|
231
263
|
onContextMenu: handleContextMenu,
|
|
264
|
+
onTouchStart: handleTouchStart,
|
|
265
|
+
onTouchMove: handleTouchMove,
|
|
266
|
+
onTouchEnd: cancelLongPress,
|
|
267
|
+
onTouchCancel: cancelLongPress,
|
|
232
268
|
children: [
|
|
233
269
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
234
270
|
"div",
|
|
@@ -1034,15 +1070,26 @@ var TableBody = ({
|
|
|
1034
1070
|
expandable,
|
|
1035
1071
|
resolvedExpandedKeys,
|
|
1036
1072
|
rowHeight = 40,
|
|
1073
|
+
totalTableWidth,
|
|
1037
1074
|
scrollAreaWidth,
|
|
1038
1075
|
accentColor,
|
|
1039
1076
|
isLoading = false,
|
|
1040
1077
|
onExpandedRowResize,
|
|
1041
|
-
maxExpandedRowHeight
|
|
1078
|
+
maxExpandedRowHeight,
|
|
1079
|
+
pinnedTopData = [],
|
|
1080
|
+
pinnedBottomData = [],
|
|
1081
|
+
gridTemplateColumns,
|
|
1082
|
+
headerHeight = 36
|
|
1042
1083
|
}) => {
|
|
1043
1084
|
const virtualItems = rowVirtualizer.getVirtualItems();
|
|
1044
1085
|
const totalSize = rowVirtualizer.getTotalSize();
|
|
1045
1086
|
const selectedKeySet = (0, import_react3.useMemo)(() => new Set(normalizedSelectedKeys), [normalizedSelectedKeys]);
|
|
1087
|
+
const allDataForSelection = (0, import_react3.useMemo)(() => {
|
|
1088
|
+
if (pinnedTopData.length === 0 && pinnedBottomData.length === 0)
|
|
1089
|
+
return data;
|
|
1090
|
+
return [...pinnedTopData, ...data, ...pinnedBottomData];
|
|
1091
|
+
}, [pinnedTopData, data, pinnedBottomData]);
|
|
1092
|
+
const pinnedRowBg = styles?.pinnedRowBg ?? styles?.pinnedBg;
|
|
1046
1093
|
const columnStyles = (0, import_react3.useMemo)(() => {
|
|
1047
1094
|
return orderedColumns.map((col, colIndex) => {
|
|
1048
1095
|
const stickyOffset = columnOffsets.get(col.key);
|
|
@@ -1099,6 +1146,8 @@ var TableBody = ({
|
|
|
1099
1146
|
"div",
|
|
1100
1147
|
{
|
|
1101
1148
|
"data-row-key": rowKey,
|
|
1149
|
+
"data-column-key": col.key,
|
|
1150
|
+
"data-bt-cell": "",
|
|
1102
1151
|
"data-selected": isSelected || void 0,
|
|
1103
1152
|
style: {
|
|
1104
1153
|
position: "absolute",
|
|
@@ -1128,7 +1177,7 @@ var TableBody = ({
|
|
|
1128
1177
|
rowSelection,
|
|
1129
1178
|
normalizedSelectedKeys,
|
|
1130
1179
|
rowKey,
|
|
1131
|
-
allData:
|
|
1180
|
+
allData: allDataForSelection,
|
|
1132
1181
|
getRowKey,
|
|
1133
1182
|
accentColor,
|
|
1134
1183
|
isLoading: isRowShimmer,
|
|
@@ -1206,6 +1255,213 @@ var TableBody = ({
|
|
|
1206
1255
|
);
|
|
1207
1256
|
})
|
|
1208
1257
|
}
|
|
1258
|
+
),
|
|
1259
|
+
pinnedTopData.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1260
|
+
"div",
|
|
1261
|
+
{
|
|
1262
|
+
style: {
|
|
1263
|
+
gridColumn: "1 / -1",
|
|
1264
|
+
gridRow: 2,
|
|
1265
|
+
height: `${totalSize}px`,
|
|
1266
|
+
position: "relative",
|
|
1267
|
+
zIndex: 20,
|
|
1268
|
+
pointerEvents: "none"
|
|
1269
|
+
},
|
|
1270
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1271
|
+
"div",
|
|
1272
|
+
{
|
|
1273
|
+
style: {
|
|
1274
|
+
position: "sticky",
|
|
1275
|
+
top: headerHeight,
|
|
1276
|
+
pointerEvents: "auto",
|
|
1277
|
+
boxShadow: "0 2px 6px -1px rgba(0,0,0,0.08)"
|
|
1278
|
+
},
|
|
1279
|
+
children: pinnedTopData.map((row, rowIdx) => {
|
|
1280
|
+
const rk = getRowKey ? getRowKey(row, rowIdx) : String(rowIdx);
|
|
1281
|
+
const isSelected = selectedKeySet.has(rk);
|
|
1282
|
+
const isExpanded = resolvedExpandedKeys?.has(rk) ?? false;
|
|
1283
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1284
|
+
"div",
|
|
1285
|
+
{
|
|
1286
|
+
className: classNames?.pinnedRow ?? "",
|
|
1287
|
+
style: {
|
|
1288
|
+
display: "grid",
|
|
1289
|
+
gridTemplateColumns: gridTemplateColumns ?? "",
|
|
1290
|
+
minWidth: totalTableWidth ? `${totalTableWidth}px` : void 0,
|
|
1291
|
+
...styles?.pinnedRow
|
|
1292
|
+
},
|
|
1293
|
+
children: orderedColumns.map((col) => {
|
|
1294
|
+
const cellValue = row[col.dataIndex];
|
|
1295
|
+
const stickyOffset = columnOffsets.get(col.key);
|
|
1296
|
+
const isPinned = Boolean(col.pinned);
|
|
1297
|
+
let zIndex = 0;
|
|
1298
|
+
if (col.key === "__select__" || col.key === "__expand__")
|
|
1299
|
+
zIndex = 11;
|
|
1300
|
+
else if (isPinned) zIndex = 2;
|
|
1301
|
+
const recordFingerprint = col.render ? JSON.stringify(row) : void 0;
|
|
1302
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1303
|
+
"div",
|
|
1304
|
+
{
|
|
1305
|
+
"data-row-key": rk,
|
|
1306
|
+
"data-column-key": col.key,
|
|
1307
|
+
"data-bt-cell": "",
|
|
1308
|
+
"data-selected": isSelected || void 0,
|
|
1309
|
+
style: {
|
|
1310
|
+
position: isPinned ? "sticky" : "relative",
|
|
1311
|
+
...col.pinned === "left" && stickyOffset !== void 0 ? { left: `${stickyOffset}px` } : {},
|
|
1312
|
+
...col.pinned === "right" && stickyOffset !== void 0 ? { right: `${stickyOffset}px` } : {},
|
|
1313
|
+
zIndex,
|
|
1314
|
+
backgroundColor: pinnedRowBg,
|
|
1315
|
+
backdropFilter: "blur(12px)",
|
|
1316
|
+
WebkitBackdropFilter: "blur(12px)",
|
|
1317
|
+
...isPinned && styles?.pinnedCell ? styles.pinnedCell : {}
|
|
1318
|
+
},
|
|
1319
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1320
|
+
"div",
|
|
1321
|
+
{
|
|
1322
|
+
style: {
|
|
1323
|
+
height: `${rowHeight}px`,
|
|
1324
|
+
position: "relative"
|
|
1325
|
+
},
|
|
1326
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1327
|
+
Cell,
|
|
1328
|
+
{
|
|
1329
|
+
value: cellValue,
|
|
1330
|
+
record: row,
|
|
1331
|
+
column: col,
|
|
1332
|
+
rowIndex: rowIdx,
|
|
1333
|
+
classNames,
|
|
1334
|
+
styles,
|
|
1335
|
+
isSelected,
|
|
1336
|
+
isExpanded,
|
|
1337
|
+
rowSelection,
|
|
1338
|
+
normalizedSelectedKeys,
|
|
1339
|
+
rowKey: rk,
|
|
1340
|
+
allData: allDataForSelection,
|
|
1341
|
+
getRowKey,
|
|
1342
|
+
accentColor,
|
|
1343
|
+
isLoading: false,
|
|
1344
|
+
recordFingerprint
|
|
1345
|
+
}
|
|
1346
|
+
)
|
|
1347
|
+
}
|
|
1348
|
+
)
|
|
1349
|
+
},
|
|
1350
|
+
col.key
|
|
1351
|
+
);
|
|
1352
|
+
})
|
|
1353
|
+
},
|
|
1354
|
+
`pinned-top-${rk}`
|
|
1355
|
+
);
|
|
1356
|
+
})
|
|
1357
|
+
}
|
|
1358
|
+
)
|
|
1359
|
+
}
|
|
1360
|
+
),
|
|
1361
|
+
pinnedBottomData.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1362
|
+
"div",
|
|
1363
|
+
{
|
|
1364
|
+
style: {
|
|
1365
|
+
gridColumn: "1 / -1",
|
|
1366
|
+
gridRow: 2,
|
|
1367
|
+
height: `${totalSize}px`,
|
|
1368
|
+
position: "relative",
|
|
1369
|
+
zIndex: 20,
|
|
1370
|
+
pointerEvents: "none",
|
|
1371
|
+
display: "flex",
|
|
1372
|
+
flexDirection: "column"
|
|
1373
|
+
},
|
|
1374
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1375
|
+
"div",
|
|
1376
|
+
{
|
|
1377
|
+
style: {
|
|
1378
|
+
marginTop: "auto",
|
|
1379
|
+
position: "sticky",
|
|
1380
|
+
bottom: 0,
|
|
1381
|
+
pointerEvents: "auto",
|
|
1382
|
+
boxShadow: "0 -2px 6px -1px rgba(0,0,0,0.08)"
|
|
1383
|
+
},
|
|
1384
|
+
children: pinnedBottomData.map((row, rowIdx) => {
|
|
1385
|
+
const rk = getRowKey ? getRowKey(row, rowIdx) : String(rowIdx);
|
|
1386
|
+
const isSelected = selectedKeySet.has(rk);
|
|
1387
|
+
const isExpanded = resolvedExpandedKeys?.has(rk) ?? false;
|
|
1388
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1389
|
+
"div",
|
|
1390
|
+
{
|
|
1391
|
+
className: classNames?.pinnedRow ?? "",
|
|
1392
|
+
style: {
|
|
1393
|
+
display: "grid",
|
|
1394
|
+
gridTemplateColumns: gridTemplateColumns ?? "",
|
|
1395
|
+
minWidth: totalTableWidth ? `${totalTableWidth}px` : void 0,
|
|
1396
|
+
...styles?.pinnedRow
|
|
1397
|
+
},
|
|
1398
|
+
children: orderedColumns.map((col) => {
|
|
1399
|
+
const cellValue = row[col.dataIndex];
|
|
1400
|
+
const stickyOffset = columnOffsets.get(col.key);
|
|
1401
|
+
const isPinned = Boolean(col.pinned);
|
|
1402
|
+
let zIndex = 0;
|
|
1403
|
+
if (col.key === "__select__" || col.key === "__expand__")
|
|
1404
|
+
zIndex = 11;
|
|
1405
|
+
else if (isPinned) zIndex = 2;
|
|
1406
|
+
const recordFingerprint = col.render ? JSON.stringify(row) : void 0;
|
|
1407
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1408
|
+
"div",
|
|
1409
|
+
{
|
|
1410
|
+
"data-row-key": rk,
|
|
1411
|
+
"data-column-key": col.key,
|
|
1412
|
+
"data-bt-cell": "",
|
|
1413
|
+
"data-selected": isSelected || void 0,
|
|
1414
|
+
style: {
|
|
1415
|
+
position: isPinned ? "sticky" : "relative",
|
|
1416
|
+
...col.pinned === "left" && stickyOffset !== void 0 ? { left: `${stickyOffset}px` } : {},
|
|
1417
|
+
...col.pinned === "right" && stickyOffset !== void 0 ? { right: `${stickyOffset}px` } : {},
|
|
1418
|
+
zIndex,
|
|
1419
|
+
backgroundColor: pinnedRowBg,
|
|
1420
|
+
backdropFilter: "blur(12px)",
|
|
1421
|
+
WebkitBackdropFilter: "blur(12px)",
|
|
1422
|
+
...isPinned && styles?.pinnedCell ? styles.pinnedCell : {}
|
|
1423
|
+
},
|
|
1424
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1425
|
+
"div",
|
|
1426
|
+
{
|
|
1427
|
+
style: {
|
|
1428
|
+
height: `${rowHeight}px`,
|
|
1429
|
+
position: "relative"
|
|
1430
|
+
},
|
|
1431
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1432
|
+
Cell,
|
|
1433
|
+
{
|
|
1434
|
+
value: cellValue,
|
|
1435
|
+
record: row,
|
|
1436
|
+
column: col,
|
|
1437
|
+
rowIndex: rowIdx,
|
|
1438
|
+
classNames,
|
|
1439
|
+
styles,
|
|
1440
|
+
isSelected,
|
|
1441
|
+
isExpanded,
|
|
1442
|
+
rowSelection,
|
|
1443
|
+
normalizedSelectedKeys,
|
|
1444
|
+
rowKey: rk,
|
|
1445
|
+
allData: allDataForSelection,
|
|
1446
|
+
getRowKey,
|
|
1447
|
+
accentColor,
|
|
1448
|
+
isLoading: false,
|
|
1449
|
+
recordFingerprint
|
|
1450
|
+
}
|
|
1451
|
+
)
|
|
1452
|
+
}
|
|
1453
|
+
)
|
|
1454
|
+
},
|
|
1455
|
+
col.key
|
|
1456
|
+
);
|
|
1457
|
+
})
|
|
1458
|
+
},
|
|
1459
|
+
`pinned-bottom-${rk}`
|
|
1460
|
+
);
|
|
1461
|
+
})
|
|
1462
|
+
}
|
|
1463
|
+
)
|
|
1464
|
+
}
|
|
1209
1465
|
)
|
|
1210
1466
|
] });
|
|
1211
1467
|
};
|
|
@@ -1241,6 +1497,8 @@ function BoltTable({
|
|
|
1241
1497
|
onColumnPin,
|
|
1242
1498
|
onColumnHide,
|
|
1243
1499
|
rowSelection,
|
|
1500
|
+
rowPinning,
|
|
1501
|
+
onRowPin,
|
|
1244
1502
|
expandable,
|
|
1245
1503
|
rowKey = "id",
|
|
1246
1504
|
onEndReached,
|
|
@@ -1781,6 +2039,73 @@ function BoltTable({
|
|
|
1781
2039
|
}
|
|
1782
2040
|
return result;
|
|
1783
2041
|
}, [data, sortState, columnFilters]);
|
|
2042
|
+
const { pinnedTopRows, pinnedBottomRows, unpinnedProcessedData } = (0, import_react4.useMemo)(() => {
|
|
2043
|
+
if (!rowPinning || !rowPinning.top?.length && !rowPinning.bottom?.length) {
|
|
2044
|
+
return {
|
|
2045
|
+
pinnedTopRows: [],
|
|
2046
|
+
pinnedBottomRows: [],
|
|
2047
|
+
unpinnedProcessedData: processedData
|
|
2048
|
+
};
|
|
2049
|
+
}
|
|
2050
|
+
const topKeySet = new Set((rowPinning.top ?? []).map(String));
|
|
2051
|
+
const bottomKeySet = new Set((rowPinning.bottom ?? []).map(String));
|
|
2052
|
+
const topMap = /* @__PURE__ */ new Map();
|
|
2053
|
+
const bottomMap = /* @__PURE__ */ new Map();
|
|
2054
|
+
const rest = [];
|
|
2055
|
+
processedData.forEach((row, idx) => {
|
|
2056
|
+
const key = getRowKey(row, idx);
|
|
2057
|
+
if (topKeySet.has(key)) topMap.set(key, row);
|
|
2058
|
+
else if (bottomKeySet.has(key)) bottomMap.set(key, row);
|
|
2059
|
+
else rest.push(row);
|
|
2060
|
+
});
|
|
2061
|
+
const orderedTop = (rowPinning.top ?? []).map((k) => topMap.get(String(k))).filter((r) => r !== void 0);
|
|
2062
|
+
const orderedBottom = (rowPinning.bottom ?? []).map((k) => bottomMap.get(String(k))).filter((r) => r !== void 0);
|
|
2063
|
+
return {
|
|
2064
|
+
pinnedTopRows: orderedTop,
|
|
2065
|
+
pinnedBottomRows: orderedBottom,
|
|
2066
|
+
unpinnedProcessedData: rest
|
|
2067
|
+
};
|
|
2068
|
+
}, [processedData, rowPinning, getRowKey]);
|
|
2069
|
+
const pinnedTopHeight = pinnedTopRows.length * rowHeight;
|
|
2070
|
+
const pinnedBottomHeight = pinnedBottomRows.length * rowHeight;
|
|
2071
|
+
const pinnedTopKeySet = (0, import_react4.useMemo)(
|
|
2072
|
+
() => new Set((rowPinning?.top ?? []).map(String)),
|
|
2073
|
+
[rowPinning?.top]
|
|
2074
|
+
);
|
|
2075
|
+
const pinnedBottomKeySet = (0, import_react4.useMemo)(
|
|
2076
|
+
() => new Set((rowPinning?.bottom ?? []).map(String)),
|
|
2077
|
+
[rowPinning?.bottom]
|
|
2078
|
+
);
|
|
2079
|
+
const [cellContextMenu, setCellContextMenu] = (0, import_react4.useState)(null);
|
|
2080
|
+
const cellMenuRef = (0, import_react4.useRef)(null);
|
|
2081
|
+
const cellLongPressTimer = (0, import_react4.useRef)(
|
|
2082
|
+
null
|
|
2083
|
+
);
|
|
2084
|
+
const cellTouchStart = (0, import_react4.useRef)(null);
|
|
2085
|
+
const cancelCellLongPress = (0, import_react4.useCallback)(() => {
|
|
2086
|
+
if (cellLongPressTimer.current) {
|
|
2087
|
+
clearTimeout(cellLongPressTimer.current);
|
|
2088
|
+
cellLongPressTimer.current = null;
|
|
2089
|
+
}
|
|
2090
|
+
cellTouchStart.current = null;
|
|
2091
|
+
}, []);
|
|
2092
|
+
import_react4.default.useEffect(() => {
|
|
2093
|
+
if (!cellContextMenu) return;
|
|
2094
|
+
const close = (e) => {
|
|
2095
|
+
if (cellMenuRef.current && cellMenuRef.current.contains(e.target))
|
|
2096
|
+
return;
|
|
2097
|
+
setCellContextMenu(null);
|
|
2098
|
+
};
|
|
2099
|
+
const onKey = (e) => {
|
|
2100
|
+
if (e.key === "Escape") setCellContextMenu(null);
|
|
2101
|
+
};
|
|
2102
|
+
document.addEventListener("mousedown", close);
|
|
2103
|
+
document.addEventListener("keydown", onKey);
|
|
2104
|
+
return () => {
|
|
2105
|
+
document.removeEventListener("mousedown", close);
|
|
2106
|
+
document.removeEventListener("keydown", onKey);
|
|
2107
|
+
};
|
|
2108
|
+
}, [cellContextMenu]);
|
|
1784
2109
|
const columnFiltersKey = Object.keys(columnFilters).sort().map((k) => `${k}:${columnFilters[k]}`).join("|");
|
|
1785
2110
|
import_react4.default.useEffect(() => {
|
|
1786
2111
|
tableAreaRef.current?.scrollTo({ top: 0 });
|
|
@@ -1788,12 +2113,12 @@ function BoltTable({
|
|
|
1788
2113
|
const pgEnabled = pagination !== false && !!pagination;
|
|
1789
2114
|
const pgSize = pgEnabled ? pagination.pageSize ?? 10 : 10;
|
|
1790
2115
|
const pgCurrent = pgEnabled ? Number(pagination.current ?? 1) : 1;
|
|
1791
|
-
const needsClientPagination = pgEnabled &&
|
|
2116
|
+
const needsClientPagination = pgEnabled && unpinnedProcessedData.length > pgSize;
|
|
1792
2117
|
const paginatedData = (0, import_react4.useMemo)(() => {
|
|
1793
|
-
if (!needsClientPagination) return
|
|
2118
|
+
if (!needsClientPagination) return unpinnedProcessedData;
|
|
1794
2119
|
const start = (pgCurrent - 1) * pgSize;
|
|
1795
|
-
return
|
|
1796
|
-
}, [
|
|
2120
|
+
return unpinnedProcessedData.slice(start, start + pgSize);
|
|
2121
|
+
}, [unpinnedProcessedData, needsClientPagination, pgCurrent, pgSize]);
|
|
1797
2122
|
const shimmerCount = pgEnabled ? pgSize : 15;
|
|
1798
2123
|
const showShimmer = isLoading && processedData.length === 0;
|
|
1799
2124
|
const shimmerData = (0, import_react4.useMemo)(() => {
|
|
@@ -1851,8 +2176,9 @@ function BoltTable({
|
|
|
1851
2176
|
return cached ? rowHeight + cached : rowHeight + expandedRowHeight;
|
|
1852
2177
|
},
|
|
1853
2178
|
overscan: 5,
|
|
1854
|
-
|
|
1855
|
-
|
|
2179
|
+
getItemKey: (index) => shimmerData ? `__shimmer_${index}__` : getRowKey(displayData[index], index),
|
|
2180
|
+
paddingStart: pinnedTopHeight,
|
|
2181
|
+
paddingEnd: pinnedBottomHeight
|
|
1856
2182
|
});
|
|
1857
2183
|
const rowVirtualizerRef = (0, import_react4.useRef)(rowVirtualizer);
|
|
1858
2184
|
rowVirtualizerRef.current = rowVirtualizer;
|
|
@@ -1892,7 +2218,7 @@ function BoltTable({
|
|
|
1892
2218
|
const activeColumn = activeId ? orderedColumns.find((col) => col.key === activeId) : null;
|
|
1893
2219
|
const currentPage = pgCurrent;
|
|
1894
2220
|
const pageSize = pgSize;
|
|
1895
|
-
const rawTotal = pgEnabled ? pagination.total ?? (needsClientPagination ?
|
|
2221
|
+
const rawTotal = pgEnabled ? pagination.total ?? (needsClientPagination ? unpinnedProcessedData.length : data.length) : data.length;
|
|
1896
2222
|
const lastKnownTotalRef = (0, import_react4.useRef)(0);
|
|
1897
2223
|
if (!isLoading || rawTotal > 0) {
|
|
1898
2224
|
lastKnownTotalRef.current = rawTotal;
|
|
@@ -2141,6 +2467,64 @@ function BoltTable({
|
|
|
2141
2467
|
position: "relative",
|
|
2142
2468
|
...isEmpty ? { height: "100%" } : {}
|
|
2143
2469
|
},
|
|
2470
|
+
onContextMenu: (e) => {
|
|
2471
|
+
const cell = e.target.closest("[data-bt-cell]");
|
|
2472
|
+
if (!cell) return;
|
|
2473
|
+
const rk = cell.dataset.rowKey;
|
|
2474
|
+
const ck = cell.dataset.columnKey;
|
|
2475
|
+
if (!rk || !ck) return;
|
|
2476
|
+
const col = freshOrderedColumns.find(
|
|
2477
|
+
(c) => c.key === ck
|
|
2478
|
+
);
|
|
2479
|
+
const hasCopy = col?.copy;
|
|
2480
|
+
const hasRowPin = !!onRowPin;
|
|
2481
|
+
if (!hasCopy && !hasRowPin) return;
|
|
2482
|
+
e.preventDefault();
|
|
2483
|
+
setCellContextMenu({
|
|
2484
|
+
x: Math.min(e.clientX, window.innerWidth - 200),
|
|
2485
|
+
y: Math.min(e.clientY, window.innerHeight - 200),
|
|
2486
|
+
rowKey: rk,
|
|
2487
|
+
columnKey: ck
|
|
2488
|
+
});
|
|
2489
|
+
},
|
|
2490
|
+
onTouchStart: (e) => {
|
|
2491
|
+
cancelCellLongPress();
|
|
2492
|
+
const cell = e.target.closest("[data-bt-cell]");
|
|
2493
|
+
if (!cell) return;
|
|
2494
|
+
const touch = e.touches[0];
|
|
2495
|
+
cellTouchStart.current = {
|
|
2496
|
+
x: touch.clientX,
|
|
2497
|
+
y: touch.clientY
|
|
2498
|
+
};
|
|
2499
|
+
const rk = cell.dataset.rowKey;
|
|
2500
|
+
const ck = cell.dataset.columnKey;
|
|
2501
|
+
cellLongPressTimer.current = setTimeout(() => {
|
|
2502
|
+
cellLongPressTimer.current = null;
|
|
2503
|
+
if (!rk || !ck) return;
|
|
2504
|
+
const col = freshOrderedColumns.find(
|
|
2505
|
+
(c) => c.key === ck
|
|
2506
|
+
);
|
|
2507
|
+
const hasCopy = col?.copy;
|
|
2508
|
+
const hasRowPin = !!onRowPin;
|
|
2509
|
+
if (!hasCopy && !hasRowPin) return;
|
|
2510
|
+
setCellContextMenu({
|
|
2511
|
+
x: Math.min(touch.clientX, window.innerWidth - 200),
|
|
2512
|
+
y: Math.min(touch.clientY, window.innerHeight - 200),
|
|
2513
|
+
rowKey: rk,
|
|
2514
|
+
columnKey: ck
|
|
2515
|
+
});
|
|
2516
|
+
}, 500);
|
|
2517
|
+
},
|
|
2518
|
+
onTouchMove: (e) => {
|
|
2519
|
+
if (!cellTouchStart.current) return;
|
|
2520
|
+
const touch = e.touches[0];
|
|
2521
|
+
const dx = touch.clientX - cellTouchStart.current.x;
|
|
2522
|
+
const dy = touch.clientY - cellTouchStart.current.y;
|
|
2523
|
+
if (Math.abs(dx) > 10 || Math.abs(dy) > 10)
|
|
2524
|
+
cancelCellLongPress();
|
|
2525
|
+
},
|
|
2526
|
+
onTouchEnd: cancelCellLongPress,
|
|
2527
|
+
onTouchCancel: cancelCellLongPress,
|
|
2144
2528
|
children: [
|
|
2145
2529
|
orderedColumns.map((column, visualIndex) => {
|
|
2146
2530
|
if (column.key === "__select__" && rowSelection) {
|
|
@@ -2329,7 +2713,11 @@ function BoltTable({
|
|
|
2329
2713
|
scrollContainerRef: tableAreaRef,
|
|
2330
2714
|
isLoading: showShimmer,
|
|
2331
2715
|
onExpandedRowResize: handleExpandedRowResize,
|
|
2332
|
-
maxExpandedRowHeight
|
|
2716
|
+
maxExpandedRowHeight,
|
|
2717
|
+
pinnedTopData: pinnedTopRows,
|
|
2718
|
+
pinnedBottomData: pinnedBottomRows,
|
|
2719
|
+
gridTemplateColumns,
|
|
2720
|
+
headerHeight: HEADER_HEIGHT
|
|
2333
2721
|
}
|
|
2334
2722
|
)
|
|
2335
2723
|
)
|
|
@@ -2635,7 +3023,166 @@ function BoltTable({
|
|
|
2635
3023
|
}
|
|
2636
3024
|
),
|
|
2637
3025
|
document.body
|
|
2638
|
-
)
|
|
3026
|
+
),
|
|
3027
|
+
cellContextMenu && typeof document !== "undefined" && (() => {
|
|
3028
|
+
const menuCol = freshOrderedColumns.find(
|
|
3029
|
+
(c) => c.key === cellContextMenu.columnKey
|
|
3030
|
+
);
|
|
3031
|
+
const isPinnedTop = pinnedTopKeySet.has(cellContextMenu.rowKey);
|
|
3032
|
+
const isPinnedBottom = pinnedBottomKeySet.has(
|
|
3033
|
+
cellContextMenu.rowKey
|
|
3034
|
+
);
|
|
3035
|
+
const hasCopy = menuCol?.copy;
|
|
3036
|
+
const hasRowPin = !!onRowPin;
|
|
3037
|
+
let menuRecord;
|
|
3038
|
+
let menuRowIndex = 0;
|
|
3039
|
+
const allRows = [
|
|
3040
|
+
...pinnedTopRows,
|
|
3041
|
+
...displayData,
|
|
3042
|
+
...pinnedBottomRows
|
|
3043
|
+
];
|
|
3044
|
+
for (let i = 0; i < allRows.length; i++) {
|
|
3045
|
+
const rk = getRowKey(allRows[i], i);
|
|
3046
|
+
if (rk === cellContextMenu.rowKey) {
|
|
3047
|
+
menuRecord = allRows[i];
|
|
3048
|
+
menuRowIndex = i;
|
|
3049
|
+
break;
|
|
3050
|
+
}
|
|
3051
|
+
}
|
|
3052
|
+
const menuValue = menuRecord && menuCol ? menuRecord[menuCol.dataIndex] : void 0;
|
|
3053
|
+
const btnStyle = {
|
|
3054
|
+
display: "flex",
|
|
3055
|
+
width: "100%",
|
|
3056
|
+
alignItems: "center",
|
|
3057
|
+
gap: 8,
|
|
3058
|
+
background: "none",
|
|
3059
|
+
border: "none",
|
|
3060
|
+
padding: "6px 12px",
|
|
3061
|
+
fontSize: 12,
|
|
3062
|
+
cursor: "pointer",
|
|
3063
|
+
color: "inherit",
|
|
3064
|
+
whiteSpace: "nowrap"
|
|
3065
|
+
};
|
|
3066
|
+
return (0, import_react_dom2.createPortal)(
|
|
3067
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
3068
|
+
"div",
|
|
3069
|
+
{
|
|
3070
|
+
ref: cellMenuRef,
|
|
3071
|
+
style: {
|
|
3072
|
+
position: "fixed",
|
|
3073
|
+
top: cellContextMenu.y,
|
|
3074
|
+
left: cellContextMenu.x,
|
|
3075
|
+
zIndex: 99999,
|
|
3076
|
+
minWidth: 170,
|
|
3077
|
+
borderRadius: 8,
|
|
3078
|
+
border: "1px solid rgba(128,128,128,0.2)",
|
|
3079
|
+
boxShadow: "0 4px 24px rgba(0,0,0,0.12)",
|
|
3080
|
+
backdropFilter: "blur(16px)",
|
|
3081
|
+
WebkitBackdropFilter: "blur(16px)",
|
|
3082
|
+
backgroundColor: "rgba(128,128,128,0.08)",
|
|
3083
|
+
padding: "4px 0",
|
|
3084
|
+
fontSize: 10
|
|
3085
|
+
},
|
|
3086
|
+
children: [
|
|
3087
|
+
hasRowPin && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
3088
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
3089
|
+
"button",
|
|
3090
|
+
{
|
|
3091
|
+
"data-bt-ctx-item": true,
|
|
3092
|
+
style: btnStyle,
|
|
3093
|
+
onClick: () => {
|
|
3094
|
+
onRowPin(
|
|
3095
|
+
cellContextMenu.rowKey,
|
|
3096
|
+
isPinnedTop ? false : "top"
|
|
3097
|
+
);
|
|
3098
|
+
setCellContextMenu(null);
|
|
3099
|
+
},
|
|
3100
|
+
children: [
|
|
3101
|
+
isPinnedTop ? icons?.pinOff ?? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3102
|
+
PinOffIcon,
|
|
3103
|
+
{
|
|
3104
|
+
style: { width: 14, height: 14, flexShrink: 0 }
|
|
3105
|
+
}
|
|
3106
|
+
) : icons?.pin ?? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3107
|
+
PinIcon,
|
|
3108
|
+
{
|
|
3109
|
+
style: { width: 14, height: 14, flexShrink: 0 }
|
|
3110
|
+
}
|
|
3111
|
+
),
|
|
3112
|
+
isPinnedTop ? "Unpin Row from Top" : "Pin Row to Top"
|
|
3113
|
+
]
|
|
3114
|
+
}
|
|
3115
|
+
),
|
|
3116
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
3117
|
+
"button",
|
|
3118
|
+
{
|
|
3119
|
+
"data-bt-ctx-item": true,
|
|
3120
|
+
style: btnStyle,
|
|
3121
|
+
onClick: () => {
|
|
3122
|
+
onRowPin(
|
|
3123
|
+
cellContextMenu.rowKey,
|
|
3124
|
+
isPinnedBottom ? false : "bottom"
|
|
3125
|
+
);
|
|
3126
|
+
setCellContextMenu(null);
|
|
3127
|
+
},
|
|
3128
|
+
children: [
|
|
3129
|
+
isPinnedBottom ? icons?.pinOff ?? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3130
|
+
PinOffIcon,
|
|
3131
|
+
{
|
|
3132
|
+
style: { width: 14, height: 14, flexShrink: 0 }
|
|
3133
|
+
}
|
|
3134
|
+
) : icons?.pin ?? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3135
|
+
PinIcon,
|
|
3136
|
+
{
|
|
3137
|
+
style: {
|
|
3138
|
+
width: 14,
|
|
3139
|
+
height: 14,
|
|
3140
|
+
flexShrink: 0,
|
|
3141
|
+
transform: "rotate(180deg)"
|
|
3142
|
+
}
|
|
3143
|
+
}
|
|
3144
|
+
),
|
|
3145
|
+
isPinnedBottom ? "Unpin Row from Bottom" : "Pin Row to Bottom"
|
|
3146
|
+
]
|
|
3147
|
+
}
|
|
3148
|
+
)
|
|
3149
|
+
] }),
|
|
3150
|
+
hasRowPin && hasCopy && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3151
|
+
"div",
|
|
3152
|
+
{
|
|
3153
|
+
style: {
|
|
3154
|
+
borderTop: "1px solid rgba(128,128,128,0.2)",
|
|
3155
|
+
margin: "4px 0"
|
|
3156
|
+
}
|
|
3157
|
+
}
|
|
3158
|
+
),
|
|
3159
|
+
hasCopy && menuRecord && menuCol && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
3160
|
+
"button",
|
|
3161
|
+
{
|
|
3162
|
+
"data-bt-ctx-item": true,
|
|
3163
|
+
style: btnStyle,
|
|
3164
|
+
onClick: () => {
|
|
3165
|
+
const text = typeof menuCol.copy === "function" ? menuCol.copy(menuValue, menuRecord, menuRowIndex) : String(menuValue ?? "");
|
|
3166
|
+
navigator.clipboard?.writeText(text);
|
|
3167
|
+
setCellContextMenu(null);
|
|
3168
|
+
},
|
|
3169
|
+
children: [
|
|
3170
|
+
icons?.copy ?? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3171
|
+
CopyIcon,
|
|
3172
|
+
{
|
|
3173
|
+
style: { width: 14, height: 14, flexShrink: 0 }
|
|
3174
|
+
}
|
|
3175
|
+
),
|
|
3176
|
+
"Copy"
|
|
3177
|
+
]
|
|
3178
|
+
}
|
|
3179
|
+
)
|
|
3180
|
+
]
|
|
3181
|
+
}
|
|
3182
|
+
),
|
|
3183
|
+
document.body
|
|
3184
|
+
);
|
|
3185
|
+
})()
|
|
2639
3186
|
] });
|
|
2640
3187
|
}
|
|
2641
3188
|
// Annotate the CommonJS export names for ESM import in node:
|